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