1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2014-2017 - Jean-André Santoni
3 *
4 * RetroArch is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with RetroArch.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include <compat/strl.h>
17 #include <file/file_path.h>
18 #include <array/rbuf.h>
19 #include <lists/string_list.h>
20 #include <string/stdstring.h>
21 #include <retro_miscellaneous.h>
22 #include <configuration.h>
23 #include <verbosity.h>
24 #include <time.h>
25 #include "../wifi_driver.h"
26 #include "../../retroarch.h"
27 #include "../../lakka.h"
28 #ifdef HAVE_GFX_WIDGETS
29 #include "../../gfx/gfx_widgets.h"
30 #endif
31
32 typedef struct
33 {
34 wifi_network_scan_t scan;
35 char command[300];
36 bool connmanctl_widgets_supported;
37 } connman_t;
38
connmanctl_init(void)39 static void *connmanctl_init(void)
40 {
41 connman_t *connman = (connman_t*)calloc(1, sizeof(connman_t));
42 #ifdef HAVE_GFX_WIDGETS
43 connman->connmanctl_widgets_supported = gfx_widgets_ready();
44 #endif
45 return connman;
46 }
47
connmanctl_free(void * data)48 static void connmanctl_free(void *data)
49 {
50 connman_t *connman = (connman_t*)data;
51 if (connman->scan.net_list)
52 RBUF_FREE(connman->scan.net_list);
53 if (data)
54 free(data);
55 }
56
connmanctl_start(void * data)57 static bool connmanctl_start(void *data)
58 {
59 (void)data;
60 return true;
61 }
62
connmanctl_stop(void * data)63 static void connmanctl_stop(void *data)
64 {
65 (void)data;
66 }
67
connmanctl_refresh_services(connman_t * connman)68 static void connmanctl_refresh_services(connman_t *connman) {
69 char line[512];
70 FILE *serv_file = popen("connmanctl services", "r");
71
72 if (connman->scan.net_list)
73 RBUF_FREE(connman->scan.net_list);
74
75 while (fgets(line, 512, serv_file))
76 {
77 int i;
78 struct string_list* list = NULL;
79 wifi_network_info_t entry;
80 size_t len = strlen(line);
81 if (len > 0 && line[len-1] == '\n')
82 line[--len] = '\0';
83
84 /* Parse lines directly and store net info directly */
85 memset(&entry, 0, sizeof(entry));
86 entry.connected = (line[2] == 'R' || line[2] == 'O');
87 entry.saved_password = (line[0] == '*');
88
89 /* connmanctl services outputs a 4 character prefixed lines,
90 * either whitespace or an identifier. i.e.:
91 * $ connmanctl services
92 * '*A0 SSID some_unique_id'
93 * ' SSID some_another_unique_id'
94 */
95 list = string_split(&line[4], " ");
96 if (!list)
97 break;
98
99 if (list->size == 0)
100 continue;
101
102 for (i = 0; i < list->size-1; i++)
103 {
104 strlcat(entry.ssid, list->elems[i].data, sizeof(entry.ssid));
105 strlcat(entry.ssid, " ", sizeof(entry.ssid)-1);
106 }
107 if (strlen(entry.ssid))
108 entry.ssid[strlen(entry.ssid)-1] = 0;
109
110 /* Store the connman network id here, for later */
111 strlcpy(entry.netid, list->elems[list->size-1].data, sizeof(entry.netid));
112 string_list_free(list);
113
114 /* Filter only wifi nets */
115 if (!strncmp(entry.netid, "wifi_", 5))
116 RBUF_PUSH(connman->scan.net_list, entry);
117 }
118
119 pclose(serv_file);
120 }
121
connmanctl_enable(void * data,bool enabled)122 static bool connmanctl_enable(void *data, bool enabled)
123 {
124 connman_t *connman = (connman_t*)data;
125 if (enabled)
126 pclose(popen("connmanctl enable wifi", "r"));
127 else
128 pclose(popen("connmanctl disable wifi", "r"));
129
130 /* Update the services, to ensure we properly show connection status */
131 connmanctl_refresh_services(connman);
132
133 return true;
134 }
135
connmanctl_tether_status(connman_t * connman)136 static bool connmanctl_tether_status(connman_t *connman)
137 {
138 /* Returns true if the tethering is active
139 * false when tethering is not active
140 */
141 size_t ln_size;
142 FILE *command_file = NULL;
143 char ln[3] = {0};
144
145 /* Following command lists 'technologies' of connman,
146 * greps the wifi + 10 following lines, then first
147 * occurance of 'Tethering', then 'True' and counts
148 * the matching lines.
149 * Expected result is either 1 (active) or 0 (not active)
150 */
151 snprintf(connman->command, sizeof(connman->command), "\
152 connmanctl technologies | \
153 grep \"/net/connman/technology/wifi\" -A 10 | \
154 grep \"^ Tethering =\" -m 1 | \
155 grep \"True\" | \
156 wc -l");
157
158 command_file = popen(connman->command, "r");
159
160 fgets(ln, sizeof(ln), command_file);
161
162 ln_size = strlen(ln)-1;
163 if (ln[ln_size] == '\n')
164 ln[ln_size] = '\0';
165
166 RARCH_LOG("[CONNMANCTL] Tether Status: command: \"%s\", output: \"%s\"\n",
167 connman->command, ln);
168
169 pclose(command_file);
170
171 if (!ln)
172 return false;
173 if (ln[0] == '0')
174 return false;
175 if (ln[0] == '1')
176 return true;
177 return false;
178 }
179
connmanctl_tether_toggle(connman_t * connman,bool switch_on,char * apname,char * passkey)180 static void connmanctl_tether_toggle(
181 connman_t *connman, bool switch_on, char* apname, char* passkey)
182 {
183 /* Starts / stops the tethering service on wi-fi device */
184 char output[256] = {0};
185 FILE *command_file = NULL;
186 settings_t *settings = config_get_ptr();
187 #ifdef HAVE_GFX_WIDGETS
188 bool widgets_active = connman->connmanctl_widgets_supported;
189 #endif
190
191 snprintf(connman->command, sizeof(connman->command), "\
192 connmanctl tether wifi %s %s %s",
193 switch_on ? "on" : "off", apname, passkey);
194
195 command_file = popen(connman->command, "r");
196
197 RARCH_LOG("[CONNMANCTL] Tether toggle: command: \"%s\"\n",
198 connman->command);
199
200 while (fgets(output, sizeof(output), command_file))
201 {
202 size_t output_size = strlen(output) - 1;
203 if (output[output_size] == '\n')
204 output[output_size] = '\0';
205
206 RARCH_LOG("[CONNMANCTL] Tether toggle: output: \"%s\"\n",
207 output);
208
209 #ifdef HAVE_GFX_WIDGETS
210 if (!widgets_active)
211 #endif
212 runloop_msg_queue_push(output, 1, 180, true,
213 NULL, MESSAGE_QUEUE_ICON_DEFAULT,
214 MESSAGE_QUEUE_CATEGORY_INFO);
215 }
216
217 pclose(command_file);
218
219 RARCH_LOG("[CONNMANCTL] Tether toggle: command finished\n");
220
221 if (switch_on)
222 {
223 if (!connmanctl_tether_status(connman))
224 configuration_set_bool(settings,
225 settings->bools.localap_enable, false);
226 }
227 else
228 {
229 if (connmanctl_tether_status(connman))
230 configuration_set_bool(settings,
231 settings->bools.localap_enable, true);
232 }
233 }
234
connmanctl_scan(void * data)235 static void connmanctl_scan(void *data)
236 {
237 settings_t *settings = config_get_ptr();
238 connman_t *connman = (connman_t*)data;
239
240 if (connmanctl_tether_status(connman))
241 {
242 runloop_msg_queue_push(msg_hash_to_str(MSG_LOCALAP_SWITCHING_OFF),
243 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
244 MESSAGE_QUEUE_CATEGORY_INFO);
245 configuration_set_bool(settings,
246 settings->bools.localap_enable, false);
247 connmanctl_tether_toggle(connman, false, "", "");
248 }
249
250 pclose(popen("connmanctl scan wifi", "r"));
251
252 runloop_msg_queue_push(msg_hash_to_str(MSG_WIFI_SCAN_COMPLETE),
253 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
254 MESSAGE_QUEUE_CATEGORY_INFO);
255
256 /* Refresh now the services, to read the discovered networks */
257 connman->scan.scan_time = time(NULL);
258 connmanctl_refresh_services(connman);
259 }
260
connmanctl_get_ssids(void * data)261 static wifi_network_scan_t* connmanctl_get_ssids(void *data)
262 {
263 unsigned i;
264 connman_t *connman = (connman_t*)data;
265
266 return &connman->scan;
267 }
268
connmanctl_ssid_is_online(void * data,unsigned i)269 static bool connmanctl_ssid_is_online(void *data, unsigned i)
270 {
271 connman_t *connman = (connman_t*)data;
272 if (!connman->scan.net_list || i >= RBUF_LEN(connman->scan.net_list))
273 return false;
274 return connman->scan.net_list[i].connected;
275 }
276
connmanctl_connection_info(void * data,wifi_network_info_t * netinfo)277 static bool connmanctl_connection_info(void *data, wifi_network_info_t *netinfo)
278 {
279 connman_t *connman = (connman_t*)data;
280 unsigned i;
281
282 if (!connman->scan.net_list)
283 return false;
284
285 for (i = 0; i < RBUF_LEN(connman->scan.net_list); i++)
286 {
287 if (connman->scan.net_list[i].connected)
288 {
289 if (netinfo)
290 memcpy(netinfo, &connman->scan.net_list[i], sizeof(*netinfo));
291 return true;
292 }
293 }
294
295 return false;
296 }
297
connmanctl_disconnect_ssid(void * data,const wifi_network_info_t * netinfo)298 static bool connmanctl_disconnect_ssid(void *data, const wifi_network_info_t* netinfo)
299 {
300 connman_t *connman = (connman_t*)data;
301
302 /* TODO:Check whether this network is actually connected */
303
304 snprintf(connman->command, sizeof(connman->command),
305 "connmanctl disconnect %s 2>&1",
306 netinfo->netid);
307
308 pclose(popen(connman->command, "r"));
309
310 /* Refresh the state since it has definitely changed */
311 connmanctl_refresh_services(connman);
312
313 return true;
314 }
315
connmanctl_connect_ssid(void * data,const wifi_network_info_t * netinfo)316 static bool connmanctl_connect_ssid(
317 void *data, const wifi_network_info_t *netinfo)
318 {
319 unsigned i;
320 bool success = false;
321 char settings_dir[PATH_MAX_LENGTH] = {0};
322 char settings_path[PATH_MAX_LENGTH] = {0};
323 char netid[160] = {0};
324 FILE *settings_file = NULL;
325 connman_t *connman = (connman_t*)data;
326 settings_t *settings = config_get_ptr();
327 static struct string_list* list = NULL;
328 #ifdef HAVE_GFX_WIDGETS
329 bool widgets_active = connman->connmanctl_widgets_supported;
330 #endif
331 strlcat(netid, netinfo->netid, sizeof(netid));
332 strlcat(settings_dir, LAKKA_CONNMAN_DIR, sizeof(settings_dir));
333 strlcat(settings_dir, netid, sizeof(settings_dir));
334
335 path_mkdir(settings_dir);
336
337 strlcat(settings_path, settings_dir, sizeof(settings_path));
338 strlcat(settings_path, "/settings", sizeof(settings_path));
339
340 if (!netinfo->saved_password)
341 {
342 settings_file = fopen(settings_path, "w");
343 if (!settings_file)
344 return false;
345 fprintf(settings_file, "[%s]\n", netid);
346 fprintf(settings_file, "Name=%s\n", netinfo->ssid);
347 fprintf(settings_file, "SSID=");
348
349 for (i = 0; i < strlen(netinfo->ssid); i++)
350 fprintf(settings_file, "%02x", (unsigned int) netinfo->ssid[i]);
351 fprintf(settings_file, "\n");
352
353 fprintf(settings_file, "Favorite=%s\n", "true");
354 fprintf(settings_file, "AutoConnect=%s\n", "true");
355 fprintf(settings_file, "Passphrase=%s\n", netinfo->passphrase);
356 fprintf(settings_file, "IPv4.method=%s\n", "dhcp");
357 fclose(settings_file);
358
359 /* connman does not pick this up automatically, so hack: */
360 system("systemctl restart connman.service");
361 }
362 else
363 {
364 /* No need for pass, config should be there already, verify it */
365 settings_file = fopen(settings_path, "r");
366 if (!settings_file)
367 {
368 /* Usually a mismatch between connman state and config, reload */
369 system("systemctl restart connman.service");
370 return false;
371 }
372 fclose(settings_file);
373 }
374
375 if (connmanctl_tether_status(connman))
376 {
377 runloop_msg_queue_push(msg_hash_to_str(MSG_LOCALAP_SWITCHING_OFF),
378 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
379 MESSAGE_QUEUE_CATEGORY_INFO);
380 configuration_set_bool(settings,
381 settings->bools.localap_enable, false);
382 connmanctl_tether_toggle(connman, false, "", "");
383 }
384
385 snprintf(connman->command, sizeof(connman->command),
386 "connmanctl connect %s",
387 netinfo->netid);
388
389 pclose(popen(connman->command, "r"));
390
391 /* Refresh status to reflect the updated state */
392 connmanctl_refresh_services(connman);
393
394 /* connman is a PITA, return code is not meaningful at all :( */
395 for (i = 0; i < RBUF_LEN(connman->scan.net_list); i++)
396 {
397 if (!strcmp(netid, connman->scan.net_list[i].netid))
398 {
399 /* Found it! Check if we are connected now */
400 success = connman->scan.net_list[i].connected;
401 if (!success)
402 {
403 /* TODO: Add forget password option, which gets rid of this hack */
404 connman->scan.net_list[i].saved_password = false;
405 unlink(settings_path);
406 }
407 }
408 }
409
410 #ifdef HAVE_GFX_WIDGETS
411 if (!widgets_active)
412 #endif
413 {
414 if (success)
415 runloop_msg_queue_push("Connected", 1, 180, true,
416 NULL, MESSAGE_QUEUE_ICON_DEFAULT,
417 MESSAGE_QUEUE_CATEGORY_INFO);
418 else
419 runloop_msg_queue_push("Connection failed!", 1, 180, true,
420 NULL, MESSAGE_QUEUE_ICON_DEFAULT,
421 MESSAGE_QUEUE_CATEGORY_INFO);
422 }
423
424 return success;
425 }
426
connmanctl_get_connected_ssid(connman_t * connman,char * ssid,size_t buffersize)427 static void connmanctl_get_connected_ssid(
428 connman_t *connman, char* ssid, size_t buffersize)
429 {
430 size_t ssid_size;
431 /* Stores the SSID of the currently connected Wi-Fi
432 * network in ssid
433 */
434 FILE *command_file = NULL;
435
436 if (buffersize < 1)
437 return;
438
439 /* Following command lists all connman services, greps
440 * only 'wifi_' services, then greps the one with
441 * 'R' (Ready) or 'O' (Online) flag and cuts out the ssid
442 */
443 snprintf(connman->command, sizeof(connman->command),
444 "connmanctl services | "
445 "grep wifi_ | "
446 "grep \"^..\\(R\\|O\\)\" | "
447 "cut -d' ' -f 2");
448
449 command_file = popen(connman->command, "r");
450
451 fgets(ssid, buffersize, command_file);
452
453 pclose(command_file);
454
455 ssid_size = strlen(ssid) - 1;
456
457 if ((ssid_size + 1) > 0)
458 if (ssid[ssid_size] == '\n')
459 ssid[ssid_size] = '\0';
460
461 RARCH_LOG("[CONNMANCTL] Get Connected SSID: command: \"%s\", output: \"%s\"\n",
462 connman->command, (ssid_size + 1) ? ssid : "<nothing_found>");
463 }
464
connmanctl_get_connected_servicename(connman_t * connman,char * servicename,size_t buffersize)465 static void connmanctl_get_connected_servicename(
466 connman_t *connman, char* servicename, size_t buffersize)
467 {
468 /* Stores the service name of currently connected Wi-Fi
469 * network in servicename
470 */
471 FILE *command_file = NULL;
472 FILE *service_file = NULL;
473 char ln[3] = {0};
474 char *temp;
475
476 if (buffersize < 1)
477 return;
478
479 temp = (char*)malloc(sizeof(char) * buffersize);
480
481 /* Following command lists all stored services in
482 * connman settings folder, which are then used in
483 * the next while loop for parsing if the service
484 * is currently online/ready
485 */
486 snprintf(connman->command, sizeof(connman->command), "\
487 for serv in %s/wifi_*/ ; do \
488 if [ -d $serv ] ; then \
489 basename $serv ; \
490 fi ; \
491 done",
492 LAKKA_CONNMAN_DIR);
493
494 command_file = popen(connman->command, "r");
495
496 RARCH_LOG("[CONNMANCTL] Testing configured services for activity: command: \"%s\"\n",
497 connman->command);
498
499 while (fgets(temp, buffersize, command_file))
500 {
501 size_t ln_size;
502 size_t temp_size = strlen(temp) - 1;
503
504 if ((temp_size + 1) > 0)
505 if (temp[temp_size] == '\n')
506 temp[temp_size] = '\0';
507
508 if ((temp_size + 1) == 0)
509 {
510 RARCH_WARN("[CONNMANCTL] Service name empty.\n");
511 continue;
512 }
513
514 /* Here we test the found service for online | ready
515 * status and count the lines. Expected results are
516 * 0 = is not active, 1 = is active
517 */
518 snprintf(connman->command, sizeof(connman->command), "\
519 connmanctl services %s | \
520 grep \"^ State = \\(online\\|ready\\)\" | \
521 wc -l",
522 temp);
523
524 service_file = popen(connman->command, "r");
525
526 fgets(ln, sizeof(ln), service_file);
527 ln_size = strlen(ln) - 1;
528
529 if (ln[ln_size] == '\n')
530 ln[ln_size] = '\0';
531
532 pclose(service_file);
533
534 RARCH_LOG("[CONNMANCTL] Service: \"%s\", status: \"%s\"\n",
535 temp, ln);
536
537 if (ln[0] == '1')
538 {
539 pclose(command_file);
540
541 strlcpy(servicename, temp, buffersize);
542
543 free(temp);
544
545 RARCH_LOG("[CONNMANCTL] Service \"%s\" considered as currently online\n",
546 servicename);
547
548 return;
549 }
550 }
551
552 pclose(command_file);
553 }
554
connmanctl_tether_start_stop(void * data,bool start,char * configfile)555 static void connmanctl_tether_start_stop(void *data, bool start, char* configfile)
556 {
557 /* Start / stop wrapper for the tethering service
558 * It also checks, if we are currently connected
559 * to a wi-fi network, which needs to be disconnected
560 * before starting the tethering service, or if the
561 * tethering service is already running / not running
562 * before performing the desired action
563 */
564 FILE *command_file = NULL;
565 char apname[64] = {0};
566 char passkey[256] = {0};
567 char ln[512] = {0};
568 char ssid[64] = {0};
569 char service[256] = {0};
570 connman_t *connman = (connman_t*)data;
571 #ifdef HAVE_GFX_WIDGETS
572 bool widgets_active = connman->connmanctl_widgets_supported;
573 #endif
574
575 RARCH_LOG("[CONNMANCTL] Tether start stop: begin\n");
576
577 if (start) /* we want to start tethering */
578 {
579 RARCH_LOG("[CONNMANCTL] Tether start stop: request to start access point\n");
580
581 if (connmanctl_tether_status(connman)) /* check if already tethering and bail out if so */
582 {
583 RARCH_LOG("[CONNMANCTL] Tether start stop: AP already running\n");
584 runloop_msg_queue_push(msg_hash_to_str(MSG_LOCALAP_ALREADY_RUNNING),
585 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
586 MESSAGE_QUEUE_CATEGORY_INFO);
587 return;
588 }
589
590 /* check if there is a config file, if not, create one, if yes, parse it */
591 if (!(command_file = fopen(configfile, "r")))
592 {
593 RARCH_WARN("[CONNMANCTL] Tether start stop: config \"%s\" does not exist\n",
594 configfile);
595
596 if (!(command_file = fopen(configfile, "w")))
597 {
598 RARCH_ERR("[CONNMANCTL] Tether start stop: cannot create config file \"%s\"\n",
599 configfile);
600
601 runloop_msg_queue_push(msg_hash_to_str(MSG_LOCALAP_ERROR_CONFIG_CREATE),
602 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
603 MESSAGE_QUEUE_CATEGORY_ERROR);
604
605 return;
606 }
607
608 RARCH_LOG("[CONNMANCTL] Tether start stop: creating new config \"%s\"\n",
609 configfile);
610
611 snprintf(apname, sizeof(apname), "LakkaAccessPoint");
612 snprintf(passkey, sizeof(passkey), "RetroArch");
613
614 fprintf(command_file, "APNAME=%s\nPASSWORD=%s", apname, passkey);
615
616 fclose(command_file);
617
618 RARCH_LOG("[CONNMANCTL] Tether start stop: new config \"%s\" created\n",
619 configfile);
620 }
621 else
622 {
623 fclose(command_file);
624
625 RARCH_LOG("[CONNMANCTL] Tether start stop: config \"%s\" exists, reading it\n",
626 configfile);
627
628 snprintf(connman->command, sizeof(connman->command), "\
629 grep -m 1 \"^APNAME=\" %s | cut -d '=' -f 2- && \
630 grep -m 1 \"^PASSWORD=\" %s | cut -d '=' -f 2-",
631 configfile, configfile);
632
633 command_file = popen(connman->command, "r");
634
635 int i = 0;
636
637 RARCH_LOG("[CONNMANCTL] Tether start stop: parsing command: \"%s\"\n",
638 connman->command);
639
640 while (fgets(ln, sizeof(ln), command_file))
641 {
642 size_t ln_size = strlen(ln) - 1;
643
644 i++;
645 if ((ln_size + 1) > 1)
646 {
647 if (ln[ln_size] == '\n')
648 ln[ln_size] = '\0';
649
650 if (i == 1)
651 {
652 strlcpy(apname, ln, sizeof(apname));
653
654 RARCH_LOG("[CONNMANCTL] Tether start stop: found APNAME: \"%s\"\n",
655 apname);
656
657 continue;
658 }
659
660 if (i == 2)
661 {
662 strlcpy(passkey, ln, sizeof(passkey));
663
664 RARCH_LOG("[CONNMANCTL] Tether start stop: found PASSWORD: \"%s\"\n",
665 passkey);
666
667 continue;
668 }
669
670 if (i > 2)
671 {
672 RARCH_WARN("[CONNMANCTL] Tether start stop: you should not get here...\n");
673 break;
674 }
675 }
676 }
677
678 pclose(command_file);
679 }
680
681 if (!apname || !passkey)
682 {
683 RARCH_ERR("[CONNMANCTL] Tether start stop: APNAME or PASSWORD missing\n");
684
685 snprintf(ln, sizeof(ln),
686 msg_hash_to_str(MSG_LOCALAP_ERROR_CONFIG_PARSE),
687 configfile);
688
689 runloop_msg_queue_push(ln,
690 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
691 MESSAGE_QUEUE_CATEGORY_ERROR);
692
693 return;
694 }
695
696 /* check if connected to a wi-fi network */
697 RARCH_LOG("[CONNMANCTL] Tether start stop: checking if not connected to a wi-fi network...\n");
698 connmanctl_get_connected_ssid(connman, ssid, sizeof(ssid));
699
700 if (strlen(ssid) != 0)
701 {
702 connmanctl_get_connected_servicename(connman, service, sizeof(service));
703
704 if (strlen(service) != 0)
705 {
706 /* disconnect from wi-fi network */
707 RARCH_LOG("[CONNMANCTL] Tether start stop: connected to SSID \"%s\", service \"%s\"\n",
708 ssid, service);
709
710 snprintf(ln, sizeof(ln),
711 msg_hash_to_str(MSG_WIFI_DISCONNECT_FROM),
712 ssid);
713
714 runloop_msg_queue_push(ln, 1, 180, true,
715 NULL, MESSAGE_QUEUE_ICON_DEFAULT,
716 MESSAGE_QUEUE_CATEGORY_INFO);
717
718 snprintf(connman->command, sizeof(connman->command), "\
719 connmanctl disconnect %s",
720 service);
721
722 command_file = popen(connman->command, "r");
723
724 RARCH_LOG("[CONNMANCTL] Tether start stop: disconnecting from service \"%s\", command: \"%s\"\n",
725 service, connman->command);
726
727 while (fgets(ln, sizeof(ln), command_file))
728 {
729 size_t ln_size = strlen(ln) - 1;
730 if (ln[ln_size] == '\n')
731 ln[ln_size] = '\0';
732
733 RARCH_LOG("[CONNMANCTL] Tether start stop: output: \"%s\"\n",
734 ln);
735
736 #ifdef HAVE_GFX_WIDGETS
737 if (!widgets_active)
738 #endif
739 runloop_msg_queue_push(ln, 1, 180, true,
740 NULL, MESSAGE_QUEUE_ICON_DEFAULT,
741 MESSAGE_QUEUE_CATEGORY_INFO);
742 }
743
744 pclose(command_file);
745
746 RARCH_LOG("[CONNMANCTL] Tether start stop: disconnect end\n");
747 }
748 }
749
750 snprintf(connman->command, sizeof(connman->command),
751 msg_hash_to_str(MSG_LOCALAP_STARTING),
752 apname, passkey);
753
754 runloop_msg_queue_push(connman->command,
755 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
756 MESSAGE_QUEUE_CATEGORY_INFO);
757 }
758 else /* we want to stop tethering */
759 {
760 RARCH_LOG("[CONNMANCTL] Tether start stop: request to stop access point\n");
761
762 if (!connmanctl_tether_status(connman)) /* check if not tethering and when not, bail out */
763 {
764 RARCH_LOG("[CONNMANCTL] Tether start stop: access point is not running\n");
765
766 runloop_msg_queue_push(msg_hash_to_str(MSG_LOCALAP_NOT_RUNNING),
767 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
768 MESSAGE_QUEUE_CATEGORY_INFO);
769
770 return;
771 }
772
773 runloop_msg_queue_push(msg_hash_to_str(MSG_LOCALAP_SWITCHING_OFF),
774 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
775 MESSAGE_QUEUE_CATEGORY_INFO);
776 }
777
778 RARCH_LOG("[CONNMANCTL] Tether start stop: calling tether_toggle()\n");
779
780 /* call the tether toggle function */
781 connmanctl_tether_toggle(connman, start, apname, passkey);
782
783 RARCH_LOG("[CONNMANCTL] Tether start stop: end\n");
784 }
785
786 wifi_driver_t wifi_connmanctl = {
787 connmanctl_init,
788 connmanctl_free,
789 connmanctl_start,
790 connmanctl_stop,
791 connmanctl_enable,
792 connmanctl_connection_info,
793 connmanctl_scan,
794 connmanctl_get_ssids,
795 connmanctl_ssid_is_online,
796 connmanctl_connect_ssid,
797 connmanctl_disconnect_ssid,
798 connmanctl_tether_start_stop,
799 "connmanctl",
800 };
801