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