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