tizen 2.3 release
[framework/connectivity/mobileap-agent.git] / src / mobileap_main.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 <fcntl.h>
19 #include <unistd.h>
20 #include <glib.h>
21 #include <dbus/dbus.h>
22 #include <dbus/dbus-glib.h>
23 #include <dbus/dbus-glib-lowlevel.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <dd-display.h>
29 #include <vconf.h>
30 #include <net_connection.h>
31 #include <appcore-common.h>
32 #include <wifi.h>
33 #include <alarm.h>
34
35 #include "mobileap_softap.h"
36 #include "mobileap_handler.h"
37 #include "mobileap_common.h"
38 #include "mobileap_bluetooth.h"
39 #include "mobileap_wifi.h"
40 #include "mobileap_usb.h"
41 #include "mobileap_network.h"
42 #include "mobileap_notification.h"
43 #include "mobileap_iptables.h"
44
45 GType tethering_object_get_type(void);
46 #define TETHERING_TYPE_OBJECT (tethering_object_get_type())
47 G_DEFINE_TYPE(TetheringObject, tethering_object, G_TYPE_OBJECT)
48
49 GMainLoop *mainloop = NULL;
50 int mobileap_state = MOBILE_AP_STATE_NONE;
51 DBusConnection *tethering_conn = NULL;
52
53 gboolean tethering_disable(TetheringObject *obj, DBusGMethodInvocation *context);
54 gboolean tethering_get_station_info(TetheringObject *obj,
55                 DBusGMethodInvocation *context);
56 gboolean tethering_get_data_packet_usage(TetheringObject *obj,
57                 DBusGMethodInvocation *context);
58
59 #include "tethering-server-stub.h"
60
61 static void tethering_object_init(TetheringObject *obj)
62 {
63         DBG("+\n");
64         g_assert(obj != NULL);
65
66         obj->init_count = 0;
67         memset(&obj->softap_settings, 0x00, sizeof(obj->softap_settings));
68 }
69
70 static void tethering_object_finalize(GObject *obj)
71 {
72         DBG("+\n");
73
74         G_OBJECT_CLASS(tethering_object_parent_class)->finalize(obj);
75 }
76
77 static void tethering_object_class_init(TetheringObjectClass *klass)
78 {
79         GObjectClass *object_class = (GObjectClass *)klass;
80         const gchar *signalNames[E_SIGNAL_MAX] = {
81                 SIGNAL_NAME_NET_CLOSED,
82                 SIGNAL_NAME_STA_CONNECT,
83                 SIGNAL_NAME_STA_DISCONNECT,
84                 SIGNAL_NAME_WIFI_TETHER_ON,
85                 SIGNAL_NAME_WIFI_TETHER_OFF,
86                 SIGNAL_NAME_USB_TETHER_ON,
87                 SIGNAL_NAME_USB_TETHER_OFF,
88                 SIGNAL_NAME_BT_TETHER_ON,
89                 SIGNAL_NAME_BT_TETHER_OFF,
90                 SIGNAL_NAME_WIFI_AP_ON,
91                 SIGNAL_NAME_WIFI_AP_OFF,
92                 SIGNAL_NAME_NO_DATA_TIMEOUT,
93                 SIGNAL_NAME_LOW_BATTERY_MODE,
94                 SIGNAL_NAME_FLIGHT_MODE,
95                 SIGNAL_NAME_POWER_SAVE_MODE,
96                 SIGNAL_NAME_SECURITY_TYPE_CHANGED,
97                 SIGNAL_NAME_SSID_VISIBILITY_CHANGED,
98                 SIGNAL_NAME_PASSPHRASE_CHANGED
99         };
100
101         int i = 0;
102
103         g_assert(klass != NULL);
104
105         object_class->finalize = tethering_object_finalize;
106
107         DBG("Creating signals\n");
108
109         for (i = 0; i < E_SIGNAL_MAX; i++) {
110                 guint signalId;
111
112                 signalId = g_signal_new(signalNames[i],
113                                         G_OBJECT_CLASS_TYPE(klass),
114                                         G_SIGNAL_RUN_LAST,
115                                         0, NULL, NULL,
116                                         g_cclosure_marshal_VOID__STRING,
117                                         G_TYPE_NONE, 1, G_TYPE_STRING);
118                 klass->signals[i] = signalId;
119         }
120
121         DBG("Binding to GLib/D-Bus\n");
122
123         dbus_g_object_type_install_info(TETHERING_TYPE_OBJECT,
124                                         &dbus_glib_tethering_object_info);
125 }
126
127 static void __add_station_info_to_array(gpointer data, gpointer user_data)
128 {
129         mobile_ap_station_info_t *si = (mobile_ap_station_info_t *)data;
130         GPtrArray *array = (GPtrArray *)user_data;
131         GValue value = {0, {{0}}};
132
133         g_value_init(&value, DBUS_STRUCT_STATIONS);
134         g_value_take_boxed(&value,
135                         dbus_g_type_specialized_construct(DBUS_STRUCT_STATIONS));
136         dbus_g_type_struct_set(&value, 0, si->interface, 1, si->ip,
137                         2, si->mac, 3, si->hostname, 4, (guint)(si->tm), G_MAXUINT);
138         g_ptr_array_add(array, g_value_get_boxed(&value));
139 }
140
141 gboolean _mobileap_set_state(int state)
142 {
143         int vconf_ret = 0;
144
145         mobileap_state |= state;
146
147         vconf_ret = vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_MODE, mobileap_state);
148         if (vconf_ret != 0) {
149                 ERR("vconf_set_int is failed : %d\n", vconf_ret);
150                 return FALSE;
151         }
152
153         return TRUE;
154 }
155
156 gboolean _mobileap_is_disabled(void)
157 {
158         return mobileap_state ? FALSE : TRUE;
159 }
160
161 gboolean _mobileap_is_enabled(int state)
162 {
163         return (mobileap_state & state) ? TRUE : FALSE;
164 }
165
166 gboolean _mobileap_is_enabled_by_type(mobile_ap_type_e type)
167 {
168         switch (type) {
169         case MOBILE_AP_TYPE_WIFI:
170                 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
171                         return TRUE;
172                 break;
173
174         case MOBILE_AP_TYPE_BT:
175                 if (_mobileap_is_enabled(MOBILE_AP_STATE_BT))
176                         return TRUE;
177                 break;
178
179         case MOBILE_AP_TYPE_USB:
180                 if (_mobileap_is_enabled(MOBILE_AP_STATE_USB))
181                         return TRUE;
182                 break;
183
184         case MOBILE_AP_TYPE_WIFI_AP:
185                 if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP))
186                         return TRUE;
187                 break;
188
189         default:
190                 ERR("Unknow type : %d\n", type);
191                 break;
192         }
193
194         return FALSE;
195 }
196
197 gboolean _mobileap_clear_state(int state)
198 {
199         int vconf_ret = 0;
200
201         mobileap_state &= (~state);
202
203         vconf_ret = vconf_set_int(VCONFKEY_MOBILE_HOTSPOT_MODE, mobileap_state);
204         if (vconf_ret != 0) {
205                 ERR("vconf_set_int is failed : %d\n", vconf_ret);
206                 return FALSE;
207         }
208
209         return TRUE;
210 }
211
212 gboolean _terminate_mobileap_agent(gpointer user_data)
213 {
214         if (mainloop == NULL) {
215                 return FALSE;
216         }
217
218         if (!_mobileap_is_disabled()) {
219                 DBG("Tethering is enabled\n");
220                 return FALSE;
221         }
222
223         if (_is_trying_network_operation()) {
224                 DBG("Network operation is going on\n");
225                 return FALSE;
226         }
227
228         if (_is_trying_wifi_operation()) {
229                 DBG("Wi-Fi operation is going on\n");
230                 return FALSE;
231         }
232
233         if (_is_trying_bt_operation()) {
234                 DBG("BT operation is going on\n");
235                 return FALSE;
236         }
237
238         if (_is_trying_usb_operation()) {
239                 DBG("USB operation is going on\n");
240                 return FALSE;
241         }
242
243         DBG("All tethering / AP's are turned off\n");
244         g_main_loop_quit(mainloop);
245         mainloop = NULL;
246
247         return FALSE;
248 }
249
250 void _block_device_sleep(void)
251 {
252         int ret = 0;
253
254         ret = display_lock_state(LCD_OFF, STAY_CUR_STATE, 0);
255         if (ret < 0)
256                 ERR("PM control [ERROR] result = %d\n", ret);
257         else
258                 DBG("PM control [SUCCESS]\n");
259 }
260
261 void _unblock_device_sleep(void)
262 {
263         int ret = 0;
264
265         ret = display_unlock_state(LCD_OFF, PM_SLEEP_MARGIN);
266         if (ret < 0)
267                 ERR("PM control [ERROR] result = %d\n", ret);
268         else
269                 DBG("PM control [SUCCESS]\n");
270 }
271
272 int _init_tethering(TetheringObject *obj)
273 {
274         int ret = MOBILE_AP_ERROR_NONE;
275
276         DBG("obj->init_count: %d\n", obj->init_count);
277
278         if (obj->init_count > 0) {
279                 obj->init_count++;
280                 return MOBILE_AP_ERROR_NONE;
281         }
282
283         if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) {
284                 ret = _open_network();
285         }
286         _mh_core_execute_dhcp_server();
287
288         obj->init_count++;
289
290         return ret;
291 }
292
293 gboolean _deinit_tethering(TetheringObject *obj)
294 {
295         DBG("obj->init_count: %d\n", obj->init_count);
296
297         guint idle_id;
298
299         if (obj->init_count > 1) {
300                 obj->init_count--;
301                 return TRUE;
302         } else if (obj->init_count <= 0) {
303                 ERR("Already deinitialized\n");
304                 obj->init_count = 0;
305                 return TRUE;
306         }
307
308         obj->init_count = 0;
309
310         _mh_core_terminate_dhcp_server();
311
312         if (!_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) {
313                 _close_network();
314         }
315
316         idle_id = g_idle_add(_terminate_mobileap_agent, NULL);
317         if (idle_id == 0) {
318                 ERR("g_idle_add is failed\n");
319         }
320
321         return TRUE;
322 }
323
324 gboolean tethering_disable(TetheringObject *obj, DBusGMethodInvocation *context)
325 {
326         int ret = MOBILE_AP_ERROR_NONE;
327
328         DBG("+\n");
329         g_assert(obj != NULL);
330         g_assert(context != NULL);
331
332         if (_mobileap_is_disabled()) {
333                 ERR("Mobile hotspot has not been enabled\n");
334                 ret = MOBILE_AP_ERROR_NOT_ENABLED;
335                 dbus_g_method_return(context, MOBILE_AP_DISABLE_CFM, ret);
336                 return FALSE;
337         }
338
339         _disable_wifi_tethering(obj);
340         _disable_bt_tethering(obj);
341         _disable_usb_tethering(obj);
342
343         dbus_g_method_return(context, MOBILE_AP_DISABLE_CFM, ret);
344
345         return TRUE;
346 }
347
348 gboolean tethering_get_station_info(TetheringObject *obj,
349                                                 DBusGMethodInvocation *context)
350 {
351         DBG("+\n");
352
353         GPtrArray *array = g_ptr_array_new();
354
355         g_assert(obj != NULL);
356         g_assert(context != NULL);
357
358         _station_info_foreach(__add_station_info_to_array, array);
359
360         dbus_g_method_return(context, MOBILE_AP_GET_STATION_INFO_CFM, array);
361         g_ptr_array_free(array, TRUE);
362
363         DBG("-\n");
364
365         return TRUE;
366 }
367
368 gboolean tethering_get_data_packet_usage(TetheringObject *obj,
369                                                 DBusGMethodInvocation *context)
370 {
371         char *if_name = NULL;
372         unsigned long long wifi_tx_bytes = 0;
373         unsigned long long wifi_rx_bytes = 0;
374         unsigned long long bt_tx_bytes = 0;
375         unsigned long long bt_rx_bytes = 0;
376         unsigned long long usb_tx_bytes = 0;
377         unsigned long long usb_rx_bytes = 0;
378         unsigned long long tx_bytes = 0;
379         unsigned long long rx_bytes = 0;
380
381         if (_get_network_interface_name(&if_name) == FALSE) {
382                 dbus_g_method_return(context, MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,
383                                 0ULL, 0ULL);
384                 return FALSE;
385         }
386
387         if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI))
388                 _get_data_usage(WIFI_IF, if_name,
389                                 &wifi_tx_bytes, &wifi_rx_bytes);
390
391         if (_mobileap_is_enabled(MOBILE_AP_STATE_BT))
392                 _get_data_usage(BT_IF_ALL, if_name,
393                                 &bt_tx_bytes, &bt_rx_bytes);
394
395         if (_mobileap_is_enabled(MOBILE_AP_STATE_USB))
396                 _get_data_usage(USB_IF, if_name,
397                                 &usb_tx_bytes, &usb_rx_bytes);
398         free(if_name);
399
400         tx_bytes = wifi_tx_bytes + bt_tx_bytes + usb_tx_bytes;
401         rx_bytes = wifi_rx_bytes + bt_rx_bytes + usb_rx_bytes;
402
403         dbus_g_method_return(context, MOBILE_AP_GET_DATA_PACKET_USAGE_CFM,
404                         tx_bytes, rx_bytes);
405
406         return TRUE;
407 }
408
409 static DBusHandlerResult __dnsmasq_signal_filter(DBusConnection *conn,
410                 DBusMessage *msg, void *user_data)
411 {
412         if (!user_data) {
413                 ERR("Invalid param\n");
414                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
415         }
416
417         char *ip_addr = NULL;
418         char *mac = NULL;
419         char *name = NULL;
420         char *bt_remote_device_name = NULL;
421         DBusError error;
422         mobile_ap_type_e type = MOBILE_AP_TYPE_MAX;
423         TetheringObject *obj = (TetheringObject *)user_data;
424         mobile_ap_station_info_t *info = NULL;
425         int n_station = 0;
426         time_t tm;
427
428         dbus_error_init(&error);
429         if (dbus_message_is_signal(msg, DNSMASQ_DBUS_INTERFACE,
430                                 "DhcpConnected")) {
431                 if (!dbus_message_get_args(msg, &error,
432                                         DBUS_TYPE_STRING, &ip_addr,
433                                         DBUS_TYPE_STRING, &mac,
434                                         DBUS_TYPE_STRING, &name,
435                                         DBUS_TYPE_INVALID)) {
436                         ERR("Cannot read message, cause: %s\n", error.message);
437                         dbus_error_free(&error);
438                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
439                 }
440                 SDBG("DhcpConnected signal : %s  %s %s\n", ip_addr, mac, name);
441                 /*
442                  * DHCP ACK received, destroy timeout if exists
443                  */
444                 _destroy_dhcp_ack_timer(mac);
445
446                 if (_get_tethering_type_from_ip(ip_addr, &type) != MOBILE_AP_ERROR_NONE)
447                         return DBUS_HANDLER_RESULT_HANDLED;
448
449                 if (_mobileap_is_enabled_by_type(type) == FALSE) {
450                         return DBUS_HANDLER_RESULT_HANDLED;
451                 }
452
453                 info = (mobile_ap_station_info_t *)malloc(sizeof(mobile_ap_station_info_t));
454                 if (info == NULL) {
455                         ERR("malloc failed\n");
456                         return DBUS_HANDLER_RESULT_HANDLED;
457                 }
458
459                 info->interface = type;
460                 g_strlcpy(info->ip, ip_addr, sizeof(info->ip));
461                 g_strlcpy(info->mac, mac, sizeof(info->mac));
462                 if (type == MOBILE_AP_TYPE_WIFI || type == MOBILE_AP_TYPE_USB ||
463                                 type == MOBILE_AP_TYPE_WIFI_AP) {
464                         if (name[0] == '\0')
465                                 info->hostname = g_strdup(MOBILE_AP_NAME_UNKNOWN);
466                         else
467                                 info->hostname = g_strdup(name);
468                 } else if (type == MOBILE_AP_TYPE_BT) {
469                         _bt_get_remote_device_name(obj, mac, &bt_remote_device_name);
470                         if (bt_remote_device_name == NULL)
471                                 info->hostname = g_strdup(MOBILE_AP_NAME_UNKNOWN);
472                         else
473                                 info->hostname = bt_remote_device_name;
474                 }
475                 time(&tm);
476                 info->tm = tm;
477
478                 if (_add_station_info(info) != MOBILE_AP_ERROR_NONE) {
479                         g_free(info->hostname);
480                         free(info);
481                         return DBUS_HANDLER_RESULT_HANDLED;
482                 }
483
484                 _get_station_count((gconstpointer)type,
485                                 _slist_find_station_by_interface, &n_station);
486                 if (n_station == 1)
487                         _stop_timeout_cb(type);
488
489                 _send_dbus_station_info("DhcpConnected", info);
490
491                 return DBUS_HANDLER_RESULT_HANDLED;
492         } else if (dbus_message_is_signal(msg, DNSMASQ_DBUS_INTERFACE,
493                                 "DhcpLeaseDeleted")) {
494                 if (!dbus_message_get_args(msg, &error,
495                                         DBUS_TYPE_STRING, &ip_addr,
496                                         DBUS_TYPE_STRING, &mac,
497                                         DBUS_TYPE_STRING, &name,
498                                         DBUS_TYPE_INVALID)) {
499                         ERR("Cannot read message, cause: %s\n", error.message);
500                         dbus_error_free(&error);
501                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
502                 }
503                 SDBG("DhcpLeaseDeleted signal : %s %s %s\n", ip_addr, mac, name);
504
505                 _remove_station_info(ip_addr, _slist_find_station_by_ip_addr);
506
507                 return DBUS_HANDLER_RESULT_HANDLED;
508         }
509
510         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
511 }
512
513 int main(int argc, char **argv)
514 {
515         const char *rule = "type='signal',interface='"DNSMASQ_DBUS_INTERFACE"'";
516
517         TetheringObject *tethering_obj = NULL;
518         DBusGConnection *tethering_bus = NULL;
519         DBusGProxy *tethering_bus_proxy = NULL;
520         DBusError dbus_error;
521         GError *error = NULL;
522         guint result = 0;
523         int ret;
524
525         DBG("+\n");
526
527 #if !GLIB_CHECK_VERSION(2,36,0)
528         g_type_init();
529 #endif
530
531         mainloop = g_main_loop_new(NULL, FALSE);
532         if (mainloop == NULL) {
533                 ERR("Couldn't create GMainLoop\n");
534                 return 0;
535         }
536
537         /* D-Bus init */
538         tethering_bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
539         if (error != NULL) {
540                 ERR("Couldn't connect to system bus[%s]\n", error->message);
541                 g_error_free(error);
542                 goto failure;
543         }
544
545         tethering_bus_proxy = dbus_g_proxy_new_for_name(tethering_bus,
546                         DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
547         if (tethering_bus_proxy == NULL) {
548                 ERR("Failed to get a proxy for D-Bus\n");
549                 goto failure;
550         }
551         if (!dbus_g_proxy_call(tethering_bus_proxy, "RequestName", &error,
552                                G_TYPE_STRING, TETHERING_SERVICE_NAME,
553                                G_TYPE_UINT, 0, G_TYPE_INVALID,
554                                G_TYPE_UINT, &result, G_TYPE_INVALID)) {
555                 ERR("dbus_g_proxy_call is failed\n");
556                 if (error) {
557                         ERR("D-Bus.RequestName RPC failed[%s]\n",
558                                         error->message);
559                         g_error_free(error);
560                 }
561                 goto failure;
562         }
563         if (result != 1) {
564                 ERR("Failed to get the primary well-known name.\n");
565                 goto failure;
566         }
567         g_object_unref(tethering_bus_proxy);
568         tethering_bus_proxy = NULL;
569
570         tethering_obj = g_object_new(TETHERING_TYPE_OBJECT, NULL);
571         if (tethering_obj == NULL) {
572                 ERR("Failed to create one Tethering instance.\n");
573                 goto failure;
574         }
575         dbus_g_connection_register_g_object(tethering_bus,
576                         TETHERING_SERVICE_OBJECT_PATH, G_OBJECT(tethering_obj));
577
578         tethering_conn = dbus_g_connection_get_connection(tethering_bus);
579         dbus_error_init(&dbus_error);
580         dbus_bus_add_match(tethering_conn, rule, &dbus_error);
581         if (dbus_error_is_set(&dbus_error)) {
582                 ERR("Cannot add D-BUS match rule, cause: %s", dbus_error.message);
583                 dbus_error_free(&dbus_error);
584                 goto failure;
585         }
586         dbus_connection_add_filter(tethering_conn, __dnsmasq_signal_filter, tethering_obj, NULL);
587
588         /* Platform modules */
589         if (appcore_set_i18n(MOBILEAP_LOCALE_COMMON_PKG, MOBILEAP_LOCALE_COMMON_RES) < 0) {
590                 ERR("appcore_set_i18n is failed\n");
591         }
592
593         if (vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_MODE, &mobileap_state) < 0) {
594                 ERR("vconf_get_int is failed\n");
595                 mobileap_state = MOBILE_AP_STATE_NONE;
596         }
597
598         _init_network((void *)tethering_obj);
599         _register_wifi_station_handler();
600         _register_vconf_cb((void *)tethering_obj);
601
602         ret = wifi_initialize();
603         if (ret != WIFI_ERROR_NONE) {
604                 ERR("wifi_initialize() is failed : %d\n", ret);
605         }
606
607         ret = alarmmgr_init(APPNAME);
608         if (ret != ALARMMGR_RESULT_SUCCESS) {
609                 ERR("alarmmgr_init(%s) is failed : %d\n", APPNAME, ret);
610         } else {
611                 ret = alarmmgr_set_cb(_sp_timeout_handler, NULL);
612                 if (ret != ALARMMGR_RESULT_SUCCESS) {
613                         ERR("alarmmgr_set_cb is failed : %d\n", ret);
614                 }
615         }
616
617         g_main_loop_run(mainloop);
618
619         alarmmgr_fini();
620
621         ret = wifi_deinitialize();
622         if (ret != WIFI_ERROR_NONE) {
623                 ERR("wifi_deinitialize() is failed : %d\n", ret);
624         }
625
626         _unregister_vconf_cb((void *)tethering_obj);
627         _unregister_wifi_station_handler();
628         _deinit_network();
629
630         dbus_connection_remove_filter(tethering_conn, __dnsmasq_signal_filter, tethering_obj);
631         dbus_bus_remove_match(tethering_conn, rule, NULL);
632
633         g_object_unref(tethering_obj);
634         dbus_g_connection_unref(tethering_bus);
635
636         DBG("-\n");
637         return 0;
638
639  failure:
640         if (tethering_obj)
641                 g_object_unref(tethering_obj);
642         if (tethering_bus_proxy)
643                 g_object_unref(tethering_bus_proxy);
644         if (tethering_bus)
645                 dbus_g_connection_unref(tethering_bus);
646
647         DBG("-\n");
648         return 0;
649 }