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