tizen 2.4 release
[framework/connectivity/mobileap-agent.git] / src / mobileap_usb.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 <stdio.h>
21 #include <string.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <gio/gio.h>
26
27 #include "mobileap_softap.h"
28 #include "mobileap_common.h"
29 #include "mobileap_usb.h"
30
31 static GDBusMethodInvocation *g_context = NULL;
32 static gboolean in_progress = FALSE;
33 static GDBusConnection *conn = NULL;
34 static guint subscription_id = 0;
35 static int usb_client_state = 0;
36
37 #define USB_SYSTEM_DEVICE_PATH  "/Org/Tizen/System/DeviceD/Usb"
38 #define USB_SYSTEM_DEVICE_IFACE "org.tizen.system.deviced.Usb"
39 #define USB_STATE_CHANGE_SIGNAL "StateChanged"
40
41 enum usbclient_state {
42         USBCLIENT_STATE_DISCONNECTED = 0x00, /* usb cable is detached */
43         USBCLIENT_STATE_CONNECTED    = 0x01, /* usb cable is attached */
44         /* usb cable is attached and available (ready to use) */
45         USBCLIENT_STATE_AVAILABLE    = 0x02,
46 };
47
48 /* GDbus Signal Handler for USB Device State Changes */
49 static void __usb_device_state_change_cb(GDBusConnection *connection,
50         const gchar *sender_name, const gchar *object_path,
51         const gchar *interface_name, const gchar *signal_name,
52         GVariant *parameters, gpointer user_data)
53 {
54         unsigned int value = 0;
55         Tethering *obj = (Tethering *)user_data;
56
57         if (NULL == parameters || NULL == obj) {
58                 ERR("Paramters Invalid \n");
59                 return;
60         }
61
62         if (strcmp(object_path, USB_SYSTEM_DEVICE_PATH) ||
63                 strcmp(interface_name, USB_SYSTEM_DEVICE_IFACE) ||
64                 strcmp(signal_name, USB_STATE_CHANGE_SIGNAL)) {
65                 ERR("Unknown DBUS Signal\n");
66                 return;
67         }
68         g_variant_get(parameters, "(u)", &value);
69         DBG("Received signal(%s), value: (%u)", signal_name, value);
70         DBG("USB connected ? (%s)", value & USBCLIENT_STATE_CONNECTED? "Yes":"No");
71         DBG("USB available ? (%s)", value & USBCLIENT_STATE_AVAILABLE? "Yes":"No");
72
73         if (USBCLIENT_STATE_DISCONNECTED == value) {
74                 _disable_usb_tethering(obj);
75
76                 if (g_context) {
77                         tethering_complete_enable_usb_tethering(obj, g_context, MOBILE_AP_ERROR_RESOURCE);
78                         g_context = NULL;
79                 } else {
80                         tethering_emit_usb_off(obj, SIGNAL_MSG_NOT_AVAIL_INTERFACE);
81                 }
82         }
83
84         usb_client_state = value;
85 }
86
87 int _dbus_register_usb_state_change_signal(void *data)
88 {
89         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
90         GError *error = NULL;
91
92 #if !GLIB_CHECK_VERSION(2,36,0)
93         g_type_init();
94 #endif
95
96         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
97         if (error) {
98                 ERR("Error occurred (%s)", error->message);
99                 g_error_free(error);
100                 ret = MOBILE_AP_ERROR_RESOURCE;
101                 goto FAIL;
102         }
103         if (!conn) {
104                 ERR("Failed to get gdbus connection");
105                 ret = MOBILE_AP_ERROR_RESOURCE;
106                 goto FAIL;
107         }
108
109         subscription_id = g_dbus_connection_signal_subscribe(
110                                                 conn, NULL, USB_SYSTEM_DEVICE_IFACE,
111                                                 USB_STATE_CHANGE_SIGNAL, USB_SYSTEM_DEVICE_PATH, NULL,
112                                                 G_DBUS_SIGNAL_FLAGS_NONE, __usb_device_state_change_cb,
113                                                 data, NULL);
114
115         if (subscription_id == 0) {
116                 ERR("Failed to subscribe signal (%d)", USB_STATE_CHANGE_SIGNAL);
117                 ret = MOBILE_AP_ERROR_RESOURCE;
118                 goto FAIL;
119         }
120
121         usb_client_state = -1;
122         DBG("Successfully Subscribed USB State Signal Handler");
123         return ret;
124
125 FAIL:
126         if (conn)
127                 g_object_unref(conn);
128         return ret;
129 }
130
131 static void __handle_usb_disconnect_cb(keynode_t *key, void *data)
132 {
133         if (key == NULL || data == NULL) {
134                 ERR("Parameter is NULL\n");
135                 return;
136         }
137
138         char *vconf_name = NULL;
139         int vconf_key;
140         Tethering *obj = (Tethering *)data;
141
142         if (!_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
143                 ERR("USB tethering is not enabled\n");
144                 return;
145         }
146
147         if (vconf_keynode_get_type(key) != VCONF_TYPE_INT) {
148                 ERR("Invalid vconf key type\n");
149                 return;
150         }
151
152         vconf_name = vconf_keynode_get_name(key);
153         if (vconf_name == NULL) {
154                 ERR("vconf_keynode_get_name is failed\n");
155                 return;
156         }
157         vconf_key = vconf_keynode_get_int(key);
158         if (vconf_key < 0) {
159                 ERR("vconf_keynode_get_int is failed\n");
160                 return;
161         }
162         SDBG("key = %s, value = %d(int)\n", vconf_name, vconf_key);
163
164         /*
165          * P140305-02551: Disconnected State is implemented from DBUS instead of
166          * VCONF key.
167          */
168         if (usb_client_state == USBCLIENT_STATE_DISCONNECTED)
169                 DBG("USB is disconnected\n");
170         else if (vconf_name && !strcmp(vconf_name, VCONFKEY_SETAPPL_USB_MODE_INT) &&
171                         vconf_key != SETTING_USB_TETHERING_MODE)
172                 SDBG("USB Mode is changed [%d]\n", vconf_key);
173         else
174                 return;
175
176         _disable_usb_tethering(obj);
177
178         if (g_context) {
179                 g_dbus_method_invocation_return_value(g_context,
180                                 g_variant_new("(uu)", MOBILE_AP_ENABLE_USB_TETHERING_CFM,
181                                                 MOBILE_AP_ERROR_RESOURCE));
182                 g_context = NULL;
183         } else {
184                 tethering_emit_usb_off(obj, SIGNAL_MSG_NOT_AVAIL_INTERFACE);
185         }
186
187         return;
188 }
189
190 static void __handle_usb_mode_change(keynode_t *key, void *data)
191 {
192         if (key == NULL || data == NULL) {
193                 ERR("Parameter is NULL\n");
194                 return;
195         }
196
197         Tethering *obj = (Tethering *)data;
198         int ret;
199         int vconf_key;
200         guint idle_id;
201
202         if (vconf_keynode_get_type(key) != VCONF_TYPE_INT) {
203                 ERR("Invalid vconf key\n");
204                 return;
205         }
206
207         vconf_key = vconf_keynode_get_int(key);
208         SDBG("key = %s, value = %d(int)\n",
209                         vconf_keynode_get_name(key), vconf_key);
210
211         if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
212                 if (vconf_key != SETTING_USB_TETHERING_MODE) {
213                         DBG("Is progressing for usb mode change\n");
214                         return;
215                 }
216
217                 DBG("USB tethering is enabled\n");
218                 vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
219                                 __handle_usb_mode_change);
220
221                 /* USB Mode change is handled while USB tethering is enabled */
222                 vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
223                                 __handle_usb_disconnect_cb, (void *)obj);
224                 ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &vconf_key);
225                 if (ret != 0) {
226                         ERR("vconf_get_int is failed. but ignored [%d]\n", ret);
227                 }
228
229                 if (vconf_key != SETTING_USB_TETHERING_MODE) {
230                         ERR("USB Mode is changed suddenly\n");
231                         _disable_usb_tethering(obj);
232                         if (g_context) {
233                                 tethering_complete_enable_usb_tethering(obj, g_context, MOBILE_AP_ERROR_RESOURCE);
234                                 g_context = NULL;
235                         }
236                         return;
237                 }
238                 _add_interface_routing(USB_IF, IP_ADDRESS_USB);
239                 _add_routing_rule(USB_IF);
240                 tethering_emit_usb_on(obj);
241                 _create_tethering_active_noti();
242                 if (g_context) {
243                         tethering_complete_enable_usb_tethering(obj, g_context, MOBILE_AP_ERROR_NONE);
244                         g_context = NULL;
245                 }
246         } else {
247                 if (vconf_key == SETTING_USB_TETHERING_MODE) {
248                         DBG("Is progressing for usb mode change\n");
249                         return;
250                 }
251
252                 DBG("USB tethering is disabled\n");
253                 vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
254                                 __handle_usb_mode_change);
255                 tethering_emit_usb_off(obj, NULL);
256                 if (g_context) {
257                         tethering_complete_disable_usb_tethering(obj, g_context, MOBILE_AP_DISABLE_USB_TETHERING_CFM, NULL);
258                         g_context = NULL;
259                 }
260
261                 in_progress = FALSE;
262                 idle_id = g_idle_add(_terminate_mobileap_agent, NULL);
263                 if (idle_id == 0)
264                         ERR("g_idle_add is failed\n");
265         }
266 }
267
268 mobile_ap_error_code_e _enable_usb_tethering(Tethering *obj)
269 {
270         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
271         int vconf_ret;
272         int usb_mode = SETTING_USB_NONE_MODE;
273
274         if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
275                 ERR("USB tethering is already enabled\n");
276                 ret = MOBILE_AP_ERROR_ALREADY_ENABLED;
277                 return ret;
278         }
279
280         if (_mobileap_is_enabled(MOBILE_AP_STATE_WIFI_AP)) {
281                 ERR("Wi-Fi AP is enabled\n");
282                 ret = MOBILE_AP_ERROR_RESOURCE;
283                 return ret;
284         }
285
286         /* Register DBus Signal Handler for USB Client State */
287         if (_dbus_register_usb_state_change_signal(obj) != MOBILE_AP_ERROR_NONE) {
288                 ERR("Failed to register dbus signal(%d)", ret);
289                 ret = MOBILE_AP_ERROR_RESOURCE;
290                 goto FAIL;
291         }
292
293         if (!_mobileap_set_state(MOBILE_AP_STATE_USB)) {
294                 ret = MOBILE_AP_ERROR_RESOURCE;
295                 goto FAIL;
296         }
297
298         ret = _init_tethering();
299         if (ret != MOBILE_AP_ERROR_NONE) {
300                 goto FAIL;
301         }
302
303         vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
304                         __handle_usb_mode_change, (void *)obj);
305
306         vconf_ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &usb_mode);
307         if (vconf_ret != 0) {
308                 ERR("Error getting vconf\n");
309                 vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
310                                 __handle_usb_mode_change);
311                 _deinit_tethering();
312                 ret = MOBILE_AP_ERROR_RESOURCE;
313                 goto FAIL;
314         }
315
316         if (usb_mode == SETTING_USB_TETHERING_MODE) {
317                 vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
318                                 __handle_usb_mode_change);
319                 _add_interface_routing(USB_IF, IP_ADDRESS_USB);
320                 _add_routing_rule(USB_IF);
321         }
322
323         DBG("-\n");
324         return MOBILE_AP_ERROR_NONE;
325
326 FAIL:
327         /* Clear DBus Signal Handler for USB Client State */
328         if (conn) {
329                 if (subscription_id > 0) {
330                         g_dbus_connection_signal_unsubscribe(conn, subscription_id);
331                         subscription_id = 0;
332                 }
333                 g_object_unref(conn);
334                 conn = NULL;
335         }
336         _mobileap_clear_state(MOBILE_AP_STATE_USB);
337
338         return ret;
339 }
340
341 mobile_ap_error_code_e _disable_usb_tethering(Tethering *obj)
342 {
343         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
344
345         if (!_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
346                 ERR("USB tethering has not been enabled\n");
347                 ret = MOBILE_AP_ERROR_NOT_ENABLED;
348                 return ret;
349         }
350
351         _deinit_tethering();
352
353         if (_remove_station_info_all(MOBILE_AP_TYPE_USB) != MOBILE_AP_ERROR_NONE) {
354                 ERR("_remove_station_info_all is failed. Ignore it\n");
355         }
356
357         /* Clear DBus Signal Handler for USB Client State */
358         if (conn) {
359                 if (subscription_id > 0) {
360                         g_dbus_connection_signal_unsubscribe(conn, subscription_id);
361                         subscription_id = 0;
362                 }
363                 g_object_unref(conn);
364                 conn = NULL;
365         }
366
367         vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
368                         __handle_usb_disconnect_cb);
369
370         _mobileap_clear_state(MOBILE_AP_STATE_USB);
371         _del_routing_rule(USB_IF);
372         _del_interface_routing(USB_IF, IP_ADDRESS_USB);
373
374         DBG("_disable_usb_tethering is done\n");
375
376         return ret;
377 }
378
379 gboolean tethering_enable_usb_tethering(Tethering *obj, GDBusMethodInvocation *context)
380 {
381         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
382         gboolean ret_val = FALSE;
383
384         DBG("+\n");
385
386         g_assert(obj != NULL);
387         g_assert(context != NULL);
388
389         if (g_context) {
390                 DBG("It is turnning on\n");
391                 tethering_complete_enable_usb_tethering(obj, g_context, MOBILE_AP_ERROR_IN_PROGRESS);
392                 return FALSE;
393         }
394
395         g_context = context;
396
397         ret = _enable_usb_tethering(obj);
398         if (ret != MOBILE_AP_ERROR_NONE) {
399                 ERR("_enable_usb_tethering() is failed : %d\n", ret);
400                 goto DONE;
401         } else {
402                 DBG("Don't need to wait for usb-setting\n");
403                 tethering_emit_usb_on(obj);
404                 _create_tethering_active_noti();
405                 ret_val = TRUE;
406         }
407
408 DONE:
409         tethering_complete_enable_usb_tethering(obj, g_context, ret);
410
411         g_context = NULL;
412
413         return ret_val;
414 }
415
416 gboolean tethering_disable_usb_tethering(Tethering *obj,
417                 GDBusMethodInvocation *context)
418 {
419         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
420         int usb_mode = SETTING_USB_NONE_MODE;
421         int vconf_ret = 0;
422
423         DBG("+\n");
424
425         g_assert(obj != NULL);
426         g_assert(context != NULL);
427
428         if (g_context) {
429                 DBG("It is turnning on\n");
430                 tethering_complete_disable_usb_tethering(obj, context,
431                                 MOBILE_AP_DISABLE_USB_TETHERING_CFM,
432                                 MOBILE_AP_ERROR_IN_PROGRESS);
433                 return FALSE;
434         }
435
436         g_context = context;
437
438         ret = _disable_usb_tethering(obj);
439         if (ret != MOBILE_AP_ERROR_NONE) {
440                 tethering_complete_disable_usb_tethering(obj, g_context,
441                                 MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret);
442                 g_context = NULL;
443                 return FALSE;
444         }
445
446         vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
447                         __handle_usb_mode_change, (void *)obj);
448         vconf_ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &usb_mode);
449         if (vconf_ret != 0) {
450                 ERR("Error getting vconf : %d. This error is ignored\n", vconf_ret);
451                 goto DONE;
452         }
453
454         if (usb_mode != SETTING_USB_TETHERING_MODE) {
455                 DBG("Don't need to wait for usb-setting\n");
456                 goto DONE;
457         }
458
459         in_progress = TRUE;
460
461         DBG("-\n");
462         return TRUE;
463
464 DONE:
465         vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
466                         __handle_usb_mode_change);
467         tethering_emit_usb_off(obj, NULL);
468         tethering_complete_disable_usb_tethering(obj, g_context,
469                         MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret);
470         g_context = NULL;
471
472         return TRUE;
473 }
474
475 gboolean _is_trying_usb_operation(void)
476 {
477         return (g_context ? TRUE : FALSE || in_progress);
478 }