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