Update for tizen_2.1(license #4)
[framework/connectivity/mobileap-agent.git] / src / mobileap_usb.c
1 /*
2  *  mobileap-agent
3  *
4  * Copyright 2012-2013  Samsung Electronics Co., Ltd
5  *
6  * Licensed under the Flora License, Version 1.1 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://floralicense.org/license
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
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 <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29
30 #include "mobileap_agent.h"
31 #include "mobileap_common.h"
32 #include "mobileap_usb.h"
33
34
35 static void __handle_usb_disconnect_cb(keynode_t *key, void *data)
36 {
37         if (key == NULL || data == NULL) {
38                 ERR("Parameter is NULL\n");
39                 return;
40         }
41
42         char *vconf_name;
43         int vconf_key;
44         TetheringObject *obj = (TetheringObject *)data;
45
46         if (!_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
47                 ERR("USB tethering is not enabled\n");
48                 return;
49         }
50
51         if (vconf_keynode_get_type(key) != VCONF_TYPE_INT) {
52                 ERR("Invalid vconf key type\n");
53                 return;
54         }
55
56         vconf_name = vconf_keynode_get_name(key);
57         vconf_key = vconf_keynode_get_int(key);
58         DBG("key = %s, value = %d(int)\n", vconf_name, vconf_key);
59
60         if (!strcmp(vconf_name, VCONFKEY_SYSMAN_USB_STATUS) &&
61                         vconf_key == VCONFKEY_SYSMAN_USB_DISCONNECTED)
62                 DBG("USB is disconnected\n");
63         else if (!strcmp(vconf_name, VCONFKEY_SETAPPL_USB_MODE_INT) &&
64                         vconf_key != SETTING_USB_TETHERING_MODE)
65                 DBG("USB Mode is changed [%d]\n", vconf_key);
66         else
67                 return;
68
69         _disable_usb_tethering(obj);
70         _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF,
71                         SIGNAL_MSG_NOT_AVAIL_INTERFACE);
72 }
73
74 static void __handle_usb_mode_change(keynode_t *key, void *data)
75 {
76         if (key == NULL || data == NULL) {
77                 ERR("Parameter is NULL\n");
78                 return;
79         }
80
81         TetheringObject *obj = (TetheringObject *)data;
82         int ret;
83         int vconf_key;
84
85         if (vconf_keynode_get_type(key) != VCONF_TYPE_INT) {
86                 ERR("Invalid vconf key\n");
87                 return;
88         }
89
90         vconf_key = vconf_keynode_get_int(key);
91         DBG("key = %s, value = %d(int)\n",
92                         vconf_keynode_get_name(key), vconf_key);
93
94         if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
95                 if (vconf_key != SETTING_USB_TETHERING_MODE) {
96                         DBG("Is progressing for usb mode change\n");
97                         return;
98                 }
99
100                 DBG("USB tethering is enabled\n");
101                 vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
102                                 __handle_usb_mode_change);
103                 _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_ON, NULL);
104                 dbus_g_method_return(obj->usb_context,
105                                 MOBILE_AP_ENABLE_USB_TETHERING_CFM,
106                                 MOBILE_AP_ERROR_NONE);
107                 obj->usb_context = NULL;
108
109                 /* USB Mode change is handled while USB tethering is enabled */
110                 vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
111                                 __handle_usb_disconnect_cb, (void *)obj);
112                 ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &vconf_key);
113                 if (ret != 0) {
114                         ERR("vconf_get_int is failed. but ignored [%d]\n", ret);
115                         return;
116                 }
117                 if (vconf_key != SETTING_USB_TETHERING_MODE) {
118                         ERR("USB Mode is changed suddenly\n");
119                         _disable_usb_tethering(obj);
120                         _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF,
121                                         SIGNAL_MSG_NOT_AVAIL_INTERFACE);
122                 }
123         } else {
124                 if (vconf_key == SETTING_USB_TETHERING_MODE) {
125                         DBG("Is progressing for usb mode change\n");
126                         return;
127                 }
128
129                 DBG("USB tethering is disabled\n");
130                 vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
131                                 __handle_usb_mode_change);
132                 _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF, NULL);
133                 dbus_g_method_return(obj->usb_context,
134                                 MOBILE_AP_DISABLE_USB_TETHERING_CFM,
135                                 MOBILE_AP_ERROR_NONE);
136                 obj->usb_context = NULL;
137         }
138 }
139
140 mobile_ap_error_code_e _enable_usb_tethering(TetheringObject *obj,
141                 DBusGMethodInvocation *context)
142 {
143         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
144         int vconf_ret;
145         int usb_mode = SETTING_USB_NONE_MODE;
146
147         if (_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
148                 ERR("USB tethering is already enabled\n");
149                 ret = MOBILE_AP_ERROR_ALREADY_ENABLED;
150                 return ret;
151         }
152
153         if (obj->usb_context) {
154                 ERR("USB request is progressing\n");
155                 ret = MOBILE_AP_ERROR_IN_PROGRESS;
156                 return ret;
157         }
158
159         vconf_notify_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
160                         __handle_usb_disconnect_cb, obj);
161         vconf_ret = vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &usb_mode);
162         if (vconf_ret != 0 || usb_mode == VCONFKEY_SYSMAN_USB_DISCONNECTED) {
163                 ERR("Error getting vconf\n");
164                 ret = MOBILE_AP_ERROR_RESOURCE;
165                 goto FAIL;
166         }
167
168         if (!_mobileap_set_state(MOBILE_AP_STATE_USB)) {
169                 ret = MOBILE_AP_ERROR_RESOURCE;
170                 goto FAIL;
171         }
172
173         if (!_init_tethering(obj)) {
174                 ret = MOBILE_AP_ERROR_RESOURCE;
175                 goto FAIL;
176         }
177
178         obj->usb_context = context;
179         vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
180                         __handle_usb_mode_change, (void *)obj);
181
182         vconf_ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &usb_mode);
183         if (vconf_ret != 0) {
184                 ERR("Error getting vconf\n");
185                 obj->usb_context = NULL;
186                 vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
187                                 __handle_usb_mode_change);
188                 _deinit_tethering(obj);
189                 ret = MOBILE_AP_ERROR_RESOURCE;
190                 goto FAIL;
191         }
192
193         if (usb_mode == SETTING_USB_TETHERING_MODE) {
194                 obj->usb_context = NULL;
195                 vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
196                                 __handle_usb_mode_change);
197         }
198
199         DBG("-\n");
200         return MOBILE_AP_ERROR_NONE;
201
202 FAIL:
203         vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
204                         __handle_usb_disconnect_cb);
205         _mobileap_clear_state(MOBILE_AP_STATE_USB);
206
207         return ret;
208 }
209
210 mobile_ap_error_code_e _disable_usb_tethering(TetheringObject *obj)
211 {
212         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
213
214         if (!_mobileap_is_enabled(MOBILE_AP_STATE_USB)) {
215                 ERR("USB tethering has not been enabled\n");
216                 ret = MOBILE_AP_ERROR_NOT_ENABLED;
217                 return ret;
218         }
219
220         _deinit_tethering(obj);
221
222         if (_remove_station_info_all(MOBILE_AP_TYPE_USB) != MOBILE_AP_ERROR_NONE) {
223                 ERR("_remove_station_info_all is failed. Ignore it\n");
224         }
225
226         vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
227                         __handle_usb_disconnect_cb);
228         vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS,
229                         __handle_usb_disconnect_cb);
230
231         _mobileap_clear_state(MOBILE_AP_STATE_USB);
232
233         DBG("_disable_usb_tethering is done\n");
234
235         return ret;
236 }
237
238 gboolean tethering_enable_usb_tethering(TetheringObject *obj,
239                 DBusGMethodInvocation *context)
240 {
241         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
242
243         DBG("+\n");
244
245         g_assert(obj != NULL);
246         g_assert(context != NULL);
247
248
249         ret = _enable_usb_tethering(obj, context);
250         if (ret != MOBILE_AP_ERROR_NONE) {
251                 ERR("_enable_usb_tethering() is failed : %d\n", ret);
252                 dbus_g_method_return(context,
253                                 MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret);
254                 return FALSE;
255         } else if (obj->usb_context == NULL) {
256                 DBG("Don't need to wait for usb-setting\n");
257                 _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_ON, NULL);
258                 dbus_g_method_return(context,
259                                 MOBILE_AP_ENABLE_USB_TETHERING_CFM, ret);
260         } else {
261                 DBG("dbus will be returned by vconf callback\n");
262         }
263
264         return TRUE;
265 }
266
267
268 gboolean tethering_disable_usb_tethering(TetheringObject *obj,
269                 DBusGMethodInvocation *context)
270 {
271         mobile_ap_error_code_e ret = MOBILE_AP_ERROR_NONE;
272         int usb_mode = SETTING_USB_NONE_MODE;
273         int vconf_ret = 0;
274
275         DBG("+\n");
276
277         g_assert(obj != NULL);
278         g_assert(context != NULL);
279
280         if (obj->usb_context) {
281                 ERR("USB request is progressing\n");
282                 ret = MOBILE_AP_ERROR_IN_PROGRESS;
283                 dbus_g_method_return(context,
284                                 MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret);
285                 return FALSE;
286         }
287
288         ret = _disable_usb_tethering(obj);
289         if (ret != MOBILE_AP_ERROR_NONE) {
290                 dbus_g_method_return(context,
291                                 MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret);
292                 return FALSE;
293         }
294
295         obj->usb_context = context;
296         vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
297                         __handle_usb_mode_change, (void *)obj);
298         vconf_ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, &usb_mode);
299         if (vconf_ret != 0) {
300                 ERR("Error getting vconf : %d. This error is ignored\n", vconf_ret);
301                 goto DONE;
302         }
303         if (usb_mode != SETTING_USB_TETHERING_MODE) {
304                 DBG("Don't need to wait for usb-setting\n");
305                 goto DONE;
306         }
307
308         DBG("-\n");
309         return TRUE;
310
311 DONE:
312         vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT,
313                         __handle_usb_mode_change);
314         _emit_mobileap_dbus_signal(obj, E_SIGNAL_USB_TETHER_OFF, NULL);
315         dbus_g_method_return(context,
316                         MOBILE_AP_DISABLE_USB_TETHERING_CFM, ret);
317         return TRUE;
318 }
319
320 static void __add_usb_station_info_to_array(GPtrArray *array, mobile_ap_station_info_t *node)
321 {
322         GValue value = {0, {{0}}};
323
324         g_value_init(&value, DBUS_STRUCT_STATION);
325         g_value_take_boxed(&value,
326                         dbus_g_type_specialized_construct(DBUS_STRUCT_STATION));
327         dbus_g_type_struct_set(&value, 0, node->ip, 1, node->mac,
328                         2, node->hostname, G_MAXUINT);
329         g_ptr_array_add(array, g_value_get_boxed(&value));
330 }
331
332 gboolean tethering_get_usb_station_info(TetheringObject *obj,
333                                                 DBusGMethodInvocation *context)
334 {
335         g_assert(obj != NULL);
336         g_assert(context != NULL);
337
338         GPtrArray *array = g_ptr_array_new();
339         mobile_ap_station_info_t *node = NULL;
340
341         if (_get_station_info((gconstpointer)MOBILE_AP_TYPE_USB,
342                                 _slist_find_station_by_interface,
343                                 &node) != MOBILE_AP_ERROR_NONE) {
344                 DBG("There is no USB station\n");
345                 dbus_g_method_return(context, array);
346                 g_ptr_array_free(array, TRUE);
347                 return TRUE;
348         }
349
350         __add_usb_station_info_to_array(array, node);
351         dbus_g_method_return(context, array);
352         g_ptr_array_free(array, TRUE);
353
354         return TRUE;
355 }
356
357 gboolean tethering_get_usb_interface_info(TetheringObject *obj,
358                 DBusGMethodInvocation *context)
359 {
360         g_assert(obj != NULL);
361         g_assert(context != NULL);
362
363         GPtrArray *array = g_ptr_array_new();
364         GValue value = {0, {{0}}};
365         struct in_addr addr;
366
367         addr.s_addr = htonl(IP_ADDRESS_USB);
368
369         g_value_init(&value, DBUS_STRUCT_INTERFACE);
370         g_value_take_boxed(&value,
371                         dbus_g_type_specialized_construct(DBUS_STRUCT_INTERFACE));
372         dbus_g_type_struct_set(&value, 0, USB_IF, 1, inet_ntoa(addr),
373                         2, inet_ntoa(addr), 3, IP_SUBNET_MASK, G_MAXUINT);
374
375         g_ptr_array_add(array, g_value_get_boxed(&value));
376         dbus_g_method_return(context, array);
377         g_ptr_array_free(array, TRUE);
378
379         return TRUE;
380 }