Indications for Wi-Fi tethering setting change are added
[platform/core/api/tethering.git] / test / tethering_test.c
1 /*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <glib.h>
22 #include <glib-object.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26
27 #include <vconf.h>
28
29 #include "tethering.h"
30
31 #define INPUT_BUF_LEN           32
32 #define DISABLE_REASON_TEXT_LEN 64
33 #define COMMON_STR_BUF_LEN      32
34
35 typedef struct {
36         tethering_enabled_cb enabled_cb;
37         tethering_disabled_cb disabled_cb;
38         tethering_connection_state_changed_cb changed_cb;
39         tethering_wifi_security_type_changed_cb security_type_changed_cb;
40         tethering_wifi_ssid_visibility_changed_cb ssid_visibility_changed_cb;
41         tethering_wifi_passphrase_changed_cb passphrase_changed_cb;
42 } __tethering_cbs;
43
44 static GMainLoop *mainloop = NULL;
45
46 static bool __is_err(tethering_error_e ret)
47 {
48         char *err_msg = NULL;
49
50         switch (ret) {
51         case TETHERING_ERROR_INVALID_PARAMETER:
52                 err_msg = "Wrong parameter is used";
53                 break;
54
55         case TETHERING_ERROR_OUT_OF_MEMORY:
56                 err_msg = "Memory is not enough";
57                 break;
58
59         case TETHERING_ERROR_NONE:
60                 return false;
61
62         case TETHERING_ERROR_NOT_ENABLED:
63                 err_msg = "Tethering is not enabled";
64                 break;
65
66         case TETHERING_ERROR_OPERATION_FAILED:
67                 err_msg = "Operation is failed";
68                 break;
69
70         case TETHERING_ERROR_RESOURCE_BUSY:
71                 err_msg = "Resource is busy";
72                 break;
73
74         default:
75                 err_msg = "This should not be happened";
76                 break;
77         }
78
79         g_print("%s\n", err_msg);
80
81         return true;
82 }
83
84 static const char *__convert_tethering_type_to_str(const tethering_type_e type)
85 {
86         static char str_buf[COMMON_STR_BUF_LEN] = {0, };
87
88         switch (type) {
89         case TETHERING_TYPE_USB:
90                 g_strlcpy(str_buf, "USB", sizeof(str_buf));
91                 break;
92
93         case TETHERING_TYPE_WIFI:
94                 g_strlcpy(str_buf, "Wi-Fi", sizeof(str_buf));
95                 break;
96
97         case TETHERING_TYPE_BT:
98                 g_strlcpy(str_buf, "Bluetooth", sizeof(str_buf));
99                 break;
100
101         default:
102                 g_strlcpy(str_buf, "Unknown", sizeof(str_buf));
103                 break;
104         }
105
106         return str_buf;
107 }
108
109 static const char *__convert_disabled_code_to_str(const tethering_disabled_cause_e code)
110 {
111         static char str_buf[DISABLE_REASON_TEXT_LEN] = {0, };
112
113         switch (code) {
114         case TETHERING_DISABLED_BY_USB_DISCONNECTION:
115                 strncpy(str_buf, "disabled due to usb disconnection", sizeof(str_buf));
116                 break;
117
118         case TETHERING_DISABLED_BY_FLIGHT_MODE:
119                 strncpy(str_buf, "disabled due to flight mode on", sizeof(str_buf));
120                 break;
121
122         case TETHERING_DISABLED_BY_LOW_BATTERY:
123                 strncpy(str_buf, "disabled due to low battery", sizeof(str_buf));
124                 break;
125
126         case TETHERING_DISABLED_BY_NETWORK_CLOSE:
127                 strncpy(str_buf, "disabled due to pdp network close", sizeof(str_buf));
128                 break;
129
130         case TETHERING_DISABLED_BY_TIMEOUT:
131                 strncpy(str_buf, "disabled due to timeout", sizeof(str_buf));
132                 break;
133
134         case TETHERING_DISABLED_BY_MDM_ON:
135                 strncpy(str_buf, "disabled due to mdm on", sizeof(str_buf));
136                 break;
137
138         case TETHERING_DISABLED_BY_OTHERS:
139                 strncpy(str_buf, "disabled by other apps", sizeof(str_buf));
140                 break;
141
142         case TETHERING_DISABLED_BY_REQUEST:
143                 strncpy(str_buf, "disabled by my request", sizeof(str_buf));
144                 break;
145
146         case TETHERING_DISABLED_BY_WIFI_ON:
147                 strncpy(str_buf, "disabled by Wi-Fi station on", sizeof(str_buf));
148                 break;
149
150         case TETHERING_DISABLED_BY_BT_OFF:
151                 strncpy(str_buf, "disabled by bluetooth off", sizeof(str_buf));
152                 break;
153
154         default:
155                 strncpy(str_buf, "disabled by unknown reason", sizeof(str_buf));
156                 break;
157         }
158
159         return str_buf;
160 }
161
162 static void __register_cbs(tethering_h th, __tethering_cbs *cbs, void *user_data)
163 {
164         tethering_error_e ret = TETHERING_ERROR_NONE;
165
166         ret = tethering_set_enabled_cb(th, TETHERING_TYPE_ALL,
167                         cbs->enabled_cb, user_data);
168         if (__is_err(ret) == true) {
169                 g_print("tethering_set_enabled_cb is failed\n");
170         }
171
172         ret = tethering_set_disabled_cb(th, TETHERING_TYPE_ALL,
173                         cbs->disabled_cb, user_data);
174         if (__is_err(ret) == true) {
175                 g_print("tethering_set_disabled_cb is failed\n");
176         }
177
178         ret = tethering_set_connection_state_changed_cb(th, TETHERING_TYPE_ALL,
179                         cbs->changed_cb, user_data);
180         if (__is_err(ret) == true) {
181                 g_print("tethering_set_connection_state_changed_cb is failed\n");
182         }
183
184         ret = tethering_wifi_set_security_type_changed_cb(th,
185                         cbs->security_type_changed_cb, user_data);
186         if (__is_err(ret) == true) {
187                 g_print("tethering_wifi_set_security_type_changed_cb is failed\n");
188         }
189
190         ret = tethering_wifi_set_ssid_visibility_changed_cb(th,
191                         cbs->ssid_visibility_changed_cb, user_data);
192         if (__is_err(ret) == true) {
193                 g_print("tethering_wifi_set_ssid_visibility_changed_cb is failed\n");
194         }
195
196         ret = tethering_wifi_set_passphrase_changed_cb(th,
197                         cbs->passphrase_changed_cb, user_data);
198         if (__is_err(ret) == true) {
199                 g_print("tethering_wifi_set_passphrase_changed_cb is failed\n");
200         }
201
202         return;
203 }
204
205 static void __deregister_cbs(tethering_h th)
206 {
207         tethering_error_e ret = TETHERING_ERROR_NONE;
208
209         ret = tethering_unset_enabled_cb(th, TETHERING_TYPE_ALL);
210         if (__is_err(ret) == true) {
211                 g_print("tethering_unset_enabled_cb is failed\n");
212         }
213
214         ret = tethering_unset_disabled_cb(th, TETHERING_TYPE_ALL);
215         if (__is_err(ret) == true) {
216                 g_print("tethering_unset_disabled_cb is failed\n");
217         }
218
219         ret = tethering_unset_connection_state_changed_cb(th, TETHERING_TYPE_ALL);
220         if (__is_err(ret) == true) {
221                 g_print("tethering_unset_connection_state_changed_cb is failed\n");
222         }
223
224         ret = tethering_wifi_unset_security_type_changed_cb(th);
225         if (__is_err(ret) == true) {
226                 g_print("tethering_wifi_unset_security_type_changed_cb is failed\n");
227         }
228
229         ret = tethering_wifi_unset_ssid_visibility_changed_cb(th);
230         if (__is_err(ret) == true) {
231                 g_print("tethering_wifi_unset_ssid_visibility_changed_cb is failed\n");
232         }
233
234         ret = tethering_wifi_unset_passphrase_changed_cb(th);
235         if (__is_err(ret) == true) {
236                 g_print("tethering_wifi_unset_passphrase_changed_cb is failed\n");
237         }
238
239         return;
240 }
241
242 /* Tethering callbacks */
243 static void __enabled_cb(tethering_error_e error, tethering_type_e type, bool is_requested, void *data)
244 {
245         if (error != TETHERING_ERROR_NONE) {
246                 if (!is_requested) {
247                         return;
248                 }
249
250                 g_print("## %s tethering is not enabled. error code[0x%X]\n",
251                                 __convert_tethering_type_to_str(type),
252                                 error);
253                 return;
254         }
255
256         if (is_requested)
257                 g_print("## %s tethering is enabled successfully\n",
258                                 __convert_tethering_type_to_str(type));
259         else
260                 g_print("## %s tethering is enabled by other app\n",
261                                 __convert_tethering_type_to_str(type));
262
263         return;
264 }
265
266 static void __disabled_cb(tethering_error_e error, tethering_type_e type, tethering_disabled_cause_e code, void *data)
267 {
268         if (error != TETHERING_ERROR_NONE) {
269                 if (code != TETHERING_DISABLED_BY_REQUEST) {
270                         return;
271                 }
272
273                 g_print("## %s tethering is not disabled. error code[0x%X]\n",
274                                 __convert_tethering_type_to_str(type), error);
275                 return;
276         }
277
278         g_print("## %s tethering is %s\n",
279                         __convert_tethering_type_to_str(type),
280                         __convert_disabled_code_to_str(code));
281
282         return;
283 }
284
285 static void __connection_state_changed_cb(tethering_client_h client, bool open, void *data)
286 {
287         tethering_client_h clone = NULL;
288         tethering_type_e type;
289         char *ip_address = NULL;
290         char *mac_address = NULL;
291         char *hostname = NULL;
292
293         tethering_client_clone(&clone, client);
294         if (clone == NULL) {
295                 g_print("tetheirng_client_clone is failed\n");
296                 return;
297         }
298
299         tethering_client_get_tethering_type(clone, &type);
300         tethering_client_get_ip_address(clone,
301                         TETHERING_ADDRESS_FAMILY_IPV4, &ip_address);
302         tethering_client_get_mac_address(clone, &mac_address);
303         tethering_client_get_name(clone, &hostname);
304
305         if (open) {
306                 g_print("## New station Type [%s], IP [%s], MAC [%s], hostname [%s]\n",
307                                 __convert_tethering_type_to_str(type),
308                                 ip_address, mac_address, hostname);
309         } else {
310                 g_print("## Disconnected station Type [%s], IP [%s], MAC [%s], hostname [%s]\n",
311                                 __convert_tethering_type_to_str(type),
312                                 ip_address, mac_address, hostname);
313         }
314
315         if (ip_address)
316                 free(ip_address);
317         if (mac_address)
318                 free(mac_address);
319         if (hostname)
320                 free(hostname);
321
322         tethering_client_destroy(clone);
323
324         return;
325 }
326
327 static void __data_usage_cb(tethering_error_e result, unsigned long long received_data,
328                 unsigned long long sent_data, void *user_data)
329 {
330         g_print("__data_usage_cb\n");
331
332         if (result != TETHERING_ERROR_NONE) {
333                 g_print("tethering_get_data_usage is failed. error[0x%X]\n", result);
334                 return;
335         }
336
337         g_print("## Received data : %llu bytes\n", received_data);
338         g_print("## Sent data : %llu bytes\n", sent_data);
339
340         return;
341 }
342
343 static bool __clients_foreach_cb(tethering_client_h client, void *data)
344 {
345         tethering_client_h clone = NULL;
346         tethering_type_e type;
347         char *ip_address = NULL;
348         char *mac_address = NULL;
349         char *hostname = NULL;
350
351         /* Clone internal information */
352         if (tethering_client_clone(&clone, client) != TETHERING_ERROR_NONE) {
353                 g_print("tethering_client_clone is failed\n");
354                 return false;
355         }
356
357         /* Get information */
358         if (tethering_client_get_tethering_type(clone, &type) != TETHERING_ERROR_NONE) {
359                 g_print("tethering_client_get_type is failed\n");
360         }
361
362         if (tethering_client_get_ip_address(clone, TETHERING_ADDRESS_FAMILY_IPV4, &ip_address) != TETHERING_ERROR_NONE) {
363                 g_print("tethering_client_get_ip_address is failed\n");
364         }
365
366         if (tethering_client_get_mac_address(clone, &mac_address) != TETHERING_ERROR_NONE) {
367                 g_print("tethering_client_get_mac_address is failed\n");
368         }
369
370         if (tethering_client_get_name(clone, &hostname) != TETHERING_ERROR_NONE) {
371                 g_print("tethering_client_get_hostname is failed\n");
372         }
373         /* End of getting information */
374
375         g_print("\n< Client Info. >\n");
376         g_print("\tType %s\n", __convert_tethering_type_to_str(type));
377         g_print("\tIP Address %s\n", ip_address);
378         g_print("\tMAC Address : %s\n", mac_address);
379         g_print("\tHostname : %s\n", hostname);
380
381         /* Destroy cloned objects */
382         if (ip_address)
383                 free(ip_address);
384         if (mac_address)
385                 free(mac_address);
386         if (hostname)
387                 free(hostname);
388
389         tethering_client_destroy(clone);
390
391         /* Continue iteration */
392         return true;
393 }
394
395 static void __security_type_changed_cb(tethering_wifi_security_type_e changed_type, void *user_data)
396 {
397         g_print("Wi-Fi Tethering Security type is changed to [%s]\n",
398                         changed_type == TETHERING_WIFI_SECURITY_TYPE_NONE ?
399                         "open" : "wpa2-psk");
400         return;
401 }
402
403 static void __ssid_visibility_changed_cb(bool changed_visible, void *user_data)
404 {
405         g_print("SSID visibility for Wi-Fi tethering changed to [%s]\n",
406                         changed_visible ? "visible" : "invisible");
407         return;
408 }
409
410 static void __passphrase_changed_cb(void *user_data)
411 {
412         g_print("Wi-Fi Tethering passphrase is changed\n");
413         return;
414 }
415 /* End of tethering callbacks */
416
417 static void __enable_tethering(tethering_h th, tethering_type_e type)
418 {
419         if (th == NULL)
420                 return;
421
422         tethering_error_e error = TETHERING_ERROR_NONE;
423
424         error = tethering_enable(th, type);
425         __is_err(error);
426
427         return;
428 }
429
430 static void __disable_tethering(tethering_h th, tethering_type_e type)
431 {
432         if (th == NULL)
433                 return;
434
435         tethering_error_e error = TETHERING_ERROR_NONE;
436
437         error = tethering_disable(th, type);
438         __is_err(error);
439
440         return;
441 }
442
443 static void __print_interface_info(tethering_h th, tethering_type_e type)
444 {
445         char *interface = NULL;
446         char *mac_address = NULL;
447         char *ip_address = NULL;
448         char *gateway_address = NULL;
449         char *subnet_mask = NULL;
450
451         if (tethering_is_enabled(th, type) == FALSE) {
452                 g_print("%s tethering is not enabled\n",
453                                 __convert_tethering_type_to_str(type));
454                 return;
455         }
456
457         tethering_get_network_interface_name(th, type, &interface);
458         tethering_get_mac_address(th, type, &mac_address);
459         tethering_get_ip_address(th, type, TETHERING_ADDRESS_FAMILY_IPV4,
460                         &ip_address);
461         tethering_get_gateway_address(th, type, TETHERING_ADDRESS_FAMILY_IPV4,
462                         &gateway_address);
463         tethering_get_subnet_mask(th, type, TETHERING_ADDRESS_FAMILY_IPV4,
464                         &subnet_mask);
465
466         g_print("interface name : %s\n", interface);
467         g_print("mac address : %s\n", mac_address);
468         g_print("ip address : %s\n", ip_address);
469         g_print("gateway address: %s\n", gateway_address);
470         g_print("subnet mask : %s\n", subnet_mask);
471
472         if (interface)
473                 free(interface);
474         if (mac_address)
475                 free(mac_address);
476         if (ip_address)
477                 free(ip_address);
478         if (gateway_address)
479                 free(gateway_address);
480         if (subnet_mask)
481                 free(subnet_mask);
482
483         return;
484 }
485
486 static void __print_wifi_tethering_setting(tethering_h th)
487 {
488         char *ssid = NULL;
489         char *passphrase = NULL;
490         bool visibility = false;
491         tethering_wifi_security_type_e security_type = TETHERING_WIFI_SECURITY_TYPE_NONE;
492
493         int error = TETHERING_ERROR_NONE;
494
495         error = tethering_wifi_get_ssid(th, &ssid);
496         if (error != TETHERING_ERROR_NONE)
497                 __is_err(error);
498         else
499                 g_print("\n\t** WiFi tethering SSID : %s\n", ssid);
500
501         error = tethering_wifi_get_passphrase(th, &passphrase);
502         if (error != TETHERING_ERROR_NONE)
503                 __is_err(error);
504         else
505                 g_print("\t** WiFi tethering passphrase : %s\n", passphrase);
506
507         error = tethering_wifi_get_ssid_visibility(th, &visibility);
508         if (error != TETHERING_ERROR_NONE)
509                 __is_err(error);
510         else
511                 g_print("\t** WiFi tethering ssid visibility : %s\n",
512                                 visibility ? "visible" : "invisible");
513
514         error = tethering_wifi_get_security_type(th, &security_type);
515         if (error != TETHERING_ERROR_NONE)
516                 __is_err(error);
517         else
518                 g_print("\t** WiFi tethering security_type : %s\n",
519                                 security_type ==
520                                 TETHERING_WIFI_SECURITY_TYPE_NONE ?
521                                 "open" : "wpa2-psk");
522
523         if (ssid)
524                 free(ssid);
525         if (passphrase)
526                 free(passphrase);
527
528         return;
529 }
530
531 void print_menu(void)
532 {
533         g_print("\nTo get client information, enter 'clients [USB | WIFI | BT | ALL]'");
534         g_print("\nTo get interface information, enter 'info [USB | WIFI | BT]'");
535         g_print("\nTo get data usage, enter 'get data_usage'");
536         g_print("\nTo enable tethering, enter 'enable [USB | WIFI | BT | ALL]'");
537         g_print("\nTo disable tethering, enter 'disable [USB | WIFI | BT | ALL]'");
538         g_print("\nTo get Wi-Fi tethering setting, enter 'get wifi_setting'");
539         g_print("\nTo set Wi-Fi tethering setting, enter '[set_security_type | set_visibility] [0 | 1]'");
540         g_print("\nTo set Wi-Fi tethering passphrase, enter 'set_passphrase [passphrase]'");
541         g_print("\nTo quit, enter 'quit'\n> ");
542
543         return;
544 }
545
546 gboolean input(GIOChannel *channel, GIOCondition condition, gpointer data)
547 {
548         tethering_h th = (tethering_h)data;
549         tethering_type_e type = 0;
550         tethering_error_e error = 0;
551         gchar buf[INPUT_BUF_LEN] = {0, };
552         gchar *cmd = NULL;
553         gchar *param = NULL;
554         gsize read = 0;
555
556 #if !GLIB_CHECK_VERSION(2, 31, 0)
557         if (g_io_channel_read(channel, buf, INPUT_BUF_LEN, &read) != G_IO_ERROR_NONE) {
558                 g_print("g_io_channel_read is failed\n");
559                 return FALSE;
560         }
561 #else
562         GError *err = NULL;
563
564         g_io_channel_read_chars(channel, buf, INPUT_BUF_LEN, &read, &err);
565         if (err != NULL) {
566                 g_print("g_io_channel_read is failed : %s\n", err->message);
567                 g_error_free(err);
568                 return FALSE;
569         }
570 #endif
571
572         buf[read] = '\0';
573         g_strstrip(buf);
574
575         cmd = buf;
576         param = strrchr(buf, ' ');
577
578         /* No parameter */
579         if (!strcmp(cmd, "quit")) {
580                 g_main_loop_quit(mainloop);
581                 return TRUE;
582         }
583
584         if (param == NULL) {
585                 print_menu();
586                 return TRUE;
587         }
588         *param = '\0';
589         param++;
590
591         /* One parameter except type */
592         if (!strcmp(cmd, "get") && !strcmp(param, "data_usage")) {
593                 error = tethering_get_data_usage(th, __data_usage_cb, NULL);
594                 if (error != TETHERING_ERROR_NONE)
595                         g_print("tethering_get_data_usage is failed [0x%X]\n",
596                                         error);
597                 goto DONE;
598         }
599
600         if (!strcmp(cmd, "get") && !strcmp(param, "wifi_setting")) {
601                 __print_wifi_tethering_setting(th);
602                 goto DONE;
603         }
604
605         if (!strcmp(cmd, "set_visibility")) {
606                 error = tethering_wifi_set_ssid_visibility(th, atoi(param));
607                 if (error != TETHERING_ERROR_NONE)
608                         g_print("tethering_wifi_set_ssid_visibility is failed [0x%X]\n",
609                                         error);
610                 goto DONE;
611         }
612
613         if (!strcmp(cmd, "set_security_type")) {
614                 error = tethering_wifi_set_security_type(th, atoi(param));
615                 if (error != TETHERING_ERROR_NONE)
616                         g_print("tethering_wifi_set_security_type is failed [0x%X]\n",
617                                         error);
618                 goto DONE;
619         }
620
621         /* This should be removed */
622         if (!strcmp(cmd, "set_passphrase")) {
623                 error = tethering_wifi_set_passphrase(th, param);
624                 if (error != TETHERING_ERROR_NONE)
625                         g_print("tethering_wifi_set_passphrase is failed [0x%X]\n",
626                                         error);
627                 goto DONE;
628         }
629
630         /* One parameter(type) */
631         if (!strcmp(param, "USB"))
632                 type = TETHERING_TYPE_USB;
633         else if (!strcmp(param, "WIFI"))
634                 type = TETHERING_TYPE_WIFI;
635         else if (!strcmp(param, "BT"))
636                 type = TETHERING_TYPE_BT;
637         else if (!strcmp(param, "ALL"))
638                 type = TETHERING_TYPE_ALL;
639         else {
640                 goto DONE;
641         }
642
643         if (!strcmp(cmd, "clients")) {
644                 error = tethering_foreach_connected_clients(th, type,
645                                 __clients_foreach_cb, NULL);
646                 if (error != TETHERING_ERROR_NONE)
647                         g_print("tethering_get_data_usage is failed [0x%X]\n",
648                                         error);
649         } else if (!strcmp(cmd, "info")) {
650                 __print_interface_info(th, type);
651         } else if (!strcmp(cmd, "enable")) {
652                 __enable_tethering(th, type);
653         } else if (!strcmp(cmd, "disable")) {
654                 __disable_tethering(th, type);
655         } else {
656                 goto DONE;
657         }
658
659 DONE:
660         print_menu();
661         return TRUE;
662 }
663
664 int main(int argc, char *argv[])
665 {
666         tethering_h th = NULL;
667         GIOChannel *stdin_channel = NULL;
668         tethering_error_e ret = TETHERING_ERROR_NONE;
669         __tethering_cbs cbs = {
670                 __enabled_cb, __disabled_cb,
671                 __connection_state_changed_cb, __security_type_changed_cb,
672                 __ssid_visibility_changed_cb, __passphrase_changed_cb};
673
674         g_type_init();
675
676         /* Create tethering handle */
677         ret = tethering_create(&th);
678         if (__is_err(ret) == true)
679                 return 0;
680
681         /* Register cbs */
682         __register_cbs(th, &cbs, NULL);
683
684         stdin_channel = g_io_channel_unix_new(0);
685         if (stdin_channel == NULL)
686                 return 0;
687
688         g_io_channel_set_encoding(stdin_channel, NULL, NULL);
689         g_io_channel_set_flags(stdin_channel,
690                         G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK, NULL);
691
692         g_io_add_watch(stdin_channel, G_IO_IN, input, (gpointer)th);
693
694         print_menu();
695
696         mainloop = g_main_loop_new (NULL, 0);
697
698         g_main_loop_run(mainloop);
699         g_main_loop_unref(mainloop);
700
701         /* Deregister cbs */
702         __deregister_cbs(th);
703
704         /* Destroy tethering handle */
705         ret = tethering_destroy(th);
706         __is_err(ret);
707
708         return 0;
709 }
710