usb_moded 0.86.0+mer64
usb_moded-modesetting.c
Go to the documentation of this file.
1
31
33
34#include "usb_moded-android.h"
35#include "usb_moded-appsync.h"
36#include "usb_moded-common.h"
38#include "usb_moded-configfs.h"
40#include "usb_moded-log.h"
41#include "usb_moded-modules.h"
42#include "usb_moded-network.h"
43#include "usb_moded-worker.h"
44
45#include <unistd.h>
46#include <fcntl.h>
47#include <mntent.h>
48#include <errno.h>
49
50/* ========================================================================= *
51 * Types
52 * ========================================================================= */
53
56typedef struct storage_info_t
57{
60
64
65/* ========================================================================= *
66 * Prototypes
67 * ========================================================================= */
68
69/* ------------------------------------------------------------------------- *
70 * MODESETTING
71 * ------------------------------------------------------------------------- */
72
73static void modesetting_track_value (const char *path, const char *text);
74void modesetting_verify_values (void);
75static char *modesetting_strip (char *str);
76static char *modesetting_read_from_file (const char *path, size_t maxsize);
77int modesetting_write_to_file_real (const char *file, int line, const char *func, const char *path, const char *text);
78bool modesetting_is_mounted (const char *mountpoint);
79bool modesetting_mount (const char *mountpoint);
80bool modesetting_unmount (const char *mountpoint);
81static gchar *modesetting_mountdev (const char *mountpoint);
82static void modesetting_free_storage_info (storage_info_t *info);
83static storage_info_t *modesetting_get_storage_info (size_t *pcount);
84static bool modesetting_enter_mass_storage_mode (const modedata_t *data);
85static int modesetting_leave_mass_storage_mode (const modedata_t *data);
86static void modesetting_report_mass_storage_blocker(const char *mountpoint, int try);
87bool modesetting_enter_dynamic_mode (void);
88void modesetting_leave_dynamic_mode (void);
89void modesetting_init (void);
90void modesetting_quit (void);
91
92/* ========================================================================= *
93 * Data
94 * ========================================================================= */
95
96static GHashTable *tracked_values = 0;
97
98/* ========================================================================= *
99 * Functions
100 * ========================================================================= */
101
102static void modesetting_track_value(const char *path, const char *text)
103{
104 LOG_REGISTER_CONTEXT;
105
106 if( !tracked_values || !path )
107 goto EXIT;
108
109 if( text )
110 g_hash_table_replace(tracked_values, g_strdup(path), g_strdup(text));
111 else
112 g_hash_table_remove(tracked_values, path);
113
114EXIT:
115 return;
116}
117
118void modesetting_verify_values(void)
119{
120 LOG_REGISTER_CONTEXT;
121
122 GHashTableIter iter;
123 gpointer key, value;
124
125 if( !tracked_values )
126 goto EXIT;
127
128 g_hash_table_iter_init(&iter, tracked_values);
129 while( g_hash_table_iter_next(&iter, &key, &value) )
130 {
131 const char *path = key;
132 const char *text = value;
133
134 char *curr = modesetting_read_from_file(path, 0x1000);
135
136 if( g_strcmp0(text, curr) ) {
137 /* There might be case mismatch between hexadecimal
138 * values used in configuration files vs what we get
139 * back when reading from kernel interfaces. */
140 if( text && curr && !g_ascii_strcasecmp(text, curr) ) {
141 log_debug("unexpected change '%s' : '%s' -> '%s' (case diff only)", path,
142 text ?: "???",
143 curr ?: "???");
144 }
145 else {
146 log_warning("unexpected change '%s' : '%s' -> '%s'", path,
147 text ?: "???",
148 curr ?: "???");
149 }
150 modesetting_track_value(path, curr);
151 }
152
153 free(curr);
154 }
155
156EXIT:
157 return;
158}
159
160static char *modesetting_strip(char *str)
161{
162 LOG_REGISTER_CONTEXT;
163
164 unsigned char *src = (unsigned char *)str;
165 unsigned char *dst = (unsigned char *)str;
166
167 while( *src > 0 && *src <= 32 ) ++src;
168
169 for( ;; )
170 {
171 while( *src > 32 ) *dst++ = *src++;
172 while( *src > 0 && *src <= 32 ) ++src;
173 if( *src == 0 ) break;
174 *dst++ = ' ';
175 }
176 *dst = 0;
177 return str;
178}
179
180static char *modesetting_read_from_file(const char *path, size_t maxsize)
181{
182 LOG_REGISTER_CONTEXT;
183
184 int fd = -1;
185 ssize_t done = 0;
186 char *data = 0;
187 char *text = 0;
188
189 if((fd = open(path, O_RDONLY)) == -1)
190 {
191 /* Silently ignore things that could result
192 * from missing / read-only files */
193 if( errno != ENOENT && errno != EACCES )
194 log_warning("%s: open: %m", path);
195 goto cleanup;
196 }
197
198 if( !(data = malloc(maxsize + 1)) )
199 goto cleanup;
200
201 if((done = read(fd, data, maxsize)) == -1)
202 {
203 log_warning("%s: read: %m", path);
204 goto cleanup;
205 }
206
207 text = realloc(data, done + 1), data = 0;
208 text[done] = 0;
209 modesetting_strip(text);
210
211cleanup:
212 free(data);
213 if(fd != -1) close(fd);
214 return text;
215}
216
217int modesetting_write_to_file_real(const char *file, int line, const char *func,
218 const char *path, const char *text)
219{
220 LOG_REGISTER_CONTEXT;
221
222 int err = -1;
223 int fd = -1;
224 size_t todo = 0;
225 char *prev = 0;
226 bool clear = false;
227 gchar *repr = 0;
228
229 /* if either path or the text to be written are not there
230 * we return an error */
231 if(!text || !path)
232 goto cleanup;
233
234 /* When attempting to clear ffs function list, writing an
235 * empty string is ignored and accomplishes nothing - while
236 * writing non-existing function clears the list but returns
237 * write error.
238 *
239 * Treat "none" (which is used as place-holder value in both
240 * configuration files and usb-moded sources) and "" similarly:
241 * - Write invalid function name to sysfs
242 * - Ignore resulting write error under default logging level
243 * - Assume reading from sysfs will result in empty string
244 */
245 if( !strcmp(path, ANDROID0_FUNCTIONS) ) {
246 if( !strcmp(text, "") || !strcmp(text, "none") ) {
247 text = "none";
248 clear = true;
249 }
250 }
251
252 repr = g_strdup(text);
253 modesetting_strip(repr);
254
255 /* If the file can be read, it also means we can later check that
256 * the file retains the value we are about to write here. */
257 if( (prev = modesetting_read_from_file(path, 0x1000)) )
258 modesetting_track_value(path, clear ? "" : repr);
259
260 log_debug("%s:%d: %s(): WRITE '%s' : '%s' --> '%s'",
261 file, line, func,
262 path, prev ?: "???", repr);
263
264 todo = strlen(text);
265
266 /* no O_CREAT -> writes only to already existing files */
267 if( (fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY))) == -1 )
268 {
269 log_warning("open(%s): %m", path);
270 goto cleanup;
271 }
272
273 while( todo > 0 )
274 {
275 ssize_t n = TEMP_FAILURE_RETRY(write(fd, text, todo));
276 if( n < 0 )
277 {
278 if( clear && errno == EINVAL )
279 log_debug("write(%s): %m (expected failure)", path);
280 else
281 log_warning("write(%s): %m", path);
282 goto cleanup;
283 }
284 todo -= n;
285 text += n;
286 }
287
288 err = 0;
289
290cleanup:
291
292 if( fd != -1 ) TEMP_FAILURE_RETRY(close(fd));
293
294 free(prev);
295 free(repr);
296
297 return err;
298}
299
300bool modesetting_is_mounted(const char *mountpoint)
301{
302 LOG_REGISTER_CONTEXT;
303
304 char cmd[256];
305 snprintf(cmd, sizeof cmd, "/bin/mountpoint -q '%s'", mountpoint);
306 return common_system(cmd) == 0;
307}
308
309bool modesetting_mount(const char *mountpoint)
310{
311 LOG_REGISTER_CONTEXT;
312
313 char cmd[256];
314 snprintf(cmd, sizeof cmd, "/bin/mount '%s'", mountpoint);
315 return common_system(cmd) == 0;
316}
317
318bool modesetting_unmount(const char *mountpoint)
319{
320 LOG_REGISTER_CONTEXT;
321
322 char cmd[256];
323 snprintf(cmd, sizeof cmd, "/bin/umount '%s'", mountpoint);
324 return common_system(cmd) == 0;
325}
326
327static gchar *modesetting_mountdev(const char *mountpoint)
328{
329 LOG_REGISTER_CONTEXT;
330
331 char *res = 0;
332 FILE *fh = 0;
333 struct mntent *me;
334
335 if( !(fh = setmntent("/etc/fstab", "r")) )
336 goto EXIT;
337
338 while( (me = getmntent(fh)) ) {
339 if( !strcmp(me->mnt_dir, mountpoint) ) {
340 res = g_strdup(me->mnt_fsname);
341 break;
342 }
343 }
344
345EXIT:
346 if( fh )
347 endmntent(fh);
348
349 log_debug("%s -> %s", mountpoint, res);
350
351 return res;
352}
353
354static void
355modesetting_free_storage_info(storage_info_t *info)
356{
357 LOG_REGISTER_CONTEXT;
358
359 if( info ) {
360 for( size_t i = 0; info[i].si_mountpoint; ++i ) {
361 g_free(info[i].si_mountpoint);
362 g_free(info[i].si_mountdevice);
363 }
364 g_free(info);
365 }
366}
367
368static storage_info_t *
369modesetting_get_storage_info(size_t *pcount)
370{
371 LOG_REGISTER_CONTEXT;
372
373 bool ack = false;
374 storage_info_t *info = 0;
375 size_t count = 0;
376 char *setting = 0;
377 gchar **array = 0;
378
379 /* Get comma separated mountpoint list from config */
380 if( !(setting = config_find_mounts()) ) {
381 log_warning("no mount points configuration");
382 goto EXIT;
383 }
384
385 /* Split mountpoint list to array and count number of items */
386 array = g_strsplit(setting, ",", 0);
387 while( array[count] )
388 ++count;
389
390 if( count < 1 ) {
391 log_warning("no mount points configured");
392 goto EXIT;
393 }
394
395 /* Convert into array of storage_info_t objects */
396 info = g_new0(storage_info_t, count + 1);
397
398 for( size_t i = 0; i < count; ++i ) {
399 const gchar *mountpnt = info[i].si_mountpoint = g_strdup(array[i]);
400
401 if( access(mountpnt, F_OK) == -1 ) {
402 log_warning("mountpoint %s does not exist", mountpnt);
403 goto EXIT;
404 }
405
406 const gchar *mountdev = info[i].si_mountdevice = modesetting_mountdev(mountpnt);
407
408 if( !mountdev ) {
409 log_warning("can't find device for %s", mountpnt);
410 goto EXIT;
411 }
412
413 if( access(mountdev, F_OK) == -1 ) {
414 log_warning("mount device %s does not exist", mountdev);
415 goto EXIT;
416 }
417 }
418
419 ack = true;
420
421EXIT:
422 if( !ack )
423 modesetting_free_storage_info(info), info = 0, count = 0;
424
425 g_strfreev(array);
426 g_free(setting);
427
428 return *pcount = count, info;
429}
430
431static bool modesetting_enter_mass_storage_mode(const modedata_t *data)
432{
433 LOG_REGISTER_CONTEXT;
434
435 bool ack = false;
436 size_t count = 0;
437 storage_info_t *info = 0;
438 int nofua = 0;
439
440 char tmp[256];
441
442 /* Get mountpoint info */
443 if( !(info = modesetting_get_storage_info(&count)) )
444 goto EXIT;
445
446 /* send unmount signal so applications can release their grasp on the fs, do this here so they have time to act */
447 umdbus_send_event_signal(USB_PRE_UNMOUNT);
448
449 /* Get "No Force Unit Access" from config */
450 nofua = config_find_sync();
451
452 /* Android usb mass-storage is expected to support only onle lun */
453 if( android_in_use()&& count > 1 ) {
454 log_warning("ignoring excess mountpoints");
455 count = 1;
456 }
457
458 /* Umount filesystems */
459 for( size_t i = 0 ; i < count; ++i )
460 {
461 const gchar *mountpnt = info[i].si_mountpoint;
462 for( int tries = 0; ; ) {
463
464 if( !modesetting_is_mounted(mountpnt) ) {
465 log_debug("%s is not mounted", mountpnt);
466 break;
467 }
468
469 if( modesetting_unmount(mountpnt) ) {
470 log_debug("unmounted %s", mountpnt);
471 break;
472 }
473
474 if( ++tries == 3 ) {
475 log_err("failed to unmount %s - giving up", mountpnt);
476 modesetting_report_mass_storage_blocker(mountpnt, 2);
477 umdbus_send_error_signal(UMOUNT_ERROR);
478 goto EXIT;
479 }
480
481 log_warning("failed to unmount %s - wait a bit", mountpnt);
482 modesetting_report_mass_storage_blocker(mountpnt, 1);
483 common_sleep(1);
484 }
485 }
486
487 /* Backend specific actions */
488 if( android_in_use() ) {
489 const gchar *mountdev = info[0].si_mountdevice;
490 android_set_enabled(false);
491 android_set_function("mass_storage");
492 android_set_attr("f_mass_storage", "lun/nofua", nofua ? "1" : "0");
493 android_set_attr("f_mass_storage", "lun/file", mountdev);
494 android_set_enabled(true);
495 }
496 else if( configfs_in_use() ) {
497 configfs_set_udc(false);
498 configfs_set_function(0);
499
500 for( size_t i = 0 ; i < count; ++i ) {
501 const gchar *mountdev = info[i].si_mountdevice;
502 if( configfs_add_mass_storage_lun(i) ) {
503 configfs_set_mass_storage_attr(i, "cdrom", "0");
504 configfs_set_mass_storage_attr(i, "nofua", nofua ? "1" : "0");
505 configfs_set_mass_storage_attr(i, "removable", "1");
506 configfs_set_mass_storage_attr(i, "ro", "0");
507 configfs_set_mass_storage_attr(i, "file", mountdev);
508 }
509 }
510 configfs_set_function("mass_storage");
511 configfs_set_udc(true);
512 }
513 else if( modules_in_use() ) {
514 /* check if the file storage module has been loaded with sufficient luns in the parameter,
515 * if not, unload and reload or load it. Since mountpoints start at 0 the amount of them is one more than their id */
516
517 snprintf(tmp, sizeof tmp,
518 "/sys/devices/platform/musb_hdrc/gadget/gadget-lun%zd/file",
519 count - 1);
520
521 if( access(tmp, R_OK) == -1 )
522 {
523 log_debug("%s does not exist, unloading and reloading mass_storage\n", tmp);
524 modules_unload_module(MODULE_MASS_STORAGE);
525 snprintf(tmp, sizeof tmp, "modprobe %s luns=%zd", MODULE_MASS_STORAGE, count);
526 log_debug("usb-load command = %s", tmp);
527 if( common_system(tmp) != 0 )
528 goto EXIT;
529 }
530
531 /* activate mounts after sleeping 1s to be sure enumeration happened and autoplay will work in windows*/
532 common_sleep(1);
533
534 for( size_t i = 0 ; i < count; ++i ) {
535 const gchar *mountdev = info[i].si_mountdevice;
536
537 snprintf(tmp, sizeof tmp, "/sys/devices/platform/musb_hdrc/gadget/gadget-lun%zd/nofua", i);
538 write_to_file(tmp, nofua ? "1" : "0");
539
540 snprintf(tmp, sizeof tmp, "/sys/devices/platform/musb_hdrc/gadget/gadget-lun%zd/file", i);
541 write_to_file(tmp, mountdev);
542 log_debug("usb lun = %s active\n", mountdev);
543 }
544 }
545 else {
546 log_err("no suitable backend for mass-storage mode");
547 goto EXIT;
548 }
549
550 /* Success */
551 ack = true;
552
553EXIT:
554
555 modesetting_free_storage_info(info);
556
557 if( ack ) {
558 /* only send data in use signal in case we actually succeed */
559 umdbus_send_event_signal(DATA_IN_USE);
560 }
561 else {
562 /* Try to undo any unmounts we might have managed to make */
563 modesetting_leave_mass_storage_mode(data);
564 }
565
566 return ack;
567}
568
569static int modesetting_leave_mass_storage_mode(const modedata_t *data)
570{
571 LOG_REGISTER_CONTEXT;
572
573 (void)data;
574
575 bool ack = false;
576 size_t count = 0;
577 storage_info_t *info = 0;
578 gchar *alt_path = 0;
579
580 char tmp[256];
581
582 /* Get mountpoint info */
583 if( !(info = modesetting_get_storage_info(&count)) )
584 goto EXIT;
585
586 /* Backend specific actions */
587 if( android_in_use() ) {
588 log_debug("Disable android mass storage\n");
589 android_set_enabled(false);
590 android_set_attr("f_mass_storage", "lun/file", "");
591 }
592 else if( configfs_in_use() ) {
593 log_debug("Disable configfs mass storage\n");
594 configfs_set_udc(false);
595 configfs_set_function(0);
596
597 // reset lun0, remove the rest altogether
598 for( size_t i = 0 ; i < count; ++i ) {
599 // reset
600 configfs_set_mass_storage_attr(i, "cdrom", "0");
601 configfs_set_mass_storage_attr(i, "nofua", "0");
602 configfs_set_mass_storage_attr(i, "removable", "1");
603 configfs_set_mass_storage_attr(i, "ro", "0");
604 configfs_set_mass_storage_attr(i, "file", "");
605 // remove
606 if( i > 0 )
607 configfs_remove_mass_storage_lun(i);
608 }
609 }
610 else if( modules_in_use() ) {
611 for( size_t i = 0 ; i < count; ++i ) {
612 snprintf(tmp, sizeof tmp, "/sys/devices/platform/musb_hdrc/gadget/gadget-lun%zd/file", i);
613 write_to_file(tmp, "");
614 log_debug("usb lun = %s inactive\n", tmp);
615 }
616 }
617 else {
618 log_err("no suitable backend for mass-storage mode");
619 }
620
621 /* Assume success i.e. all the mountpoints that could have been
622 * unmounted due to mass-storage mode are mounted again. */
623 ack = true;
624
625 /* Remount filesystems */
626
627 /* TODO FIXME list of mountpoints, but singular alt mountpoint? */
628 alt_path = config_find_alt_mount();
629
630 for( size_t i = 0 ; i < count; ++i ) {
631 const char *mountpnt = info[i].si_mountpoint;
632
633 if( modesetting_is_mounted(mountpnt) ) {
634 log_debug("%s is already mounted", mountpnt);
635 continue;
636 }
637
638 if( modesetting_mount(mountpnt) ) {
639 log_debug("mounted %s", mountpnt);
640 continue;
641 }
642
643 /* At least one mountpoint could not be restored = failure */
644 ack = false;
645
646 if( !alt_path ) {
647 log_err("failed to mount %s - no alt mountpoint defined", mountpnt);
648 }
649 else {
650 // TODO what is the point of this all???
651 log_err("failed to mount %s - trying ro tmpfs as %s", mountpnt, alt_path);
652 snprintf(tmp, sizeof tmp, "mount -t tmpfs tmpfs -o ro --size=512K %s", alt_path);
653 }
654 }
655
656EXIT:
657 modesetting_free_storage_info(info);
658 free(alt_path);
659
660 if( !ack )
661 umdbus_send_error_signal(RE_MOUNT_FAILED);
662
663 return ack;
664}
665
666static void modesetting_report_mass_storage_blocker(const char *mountpoint, int try)
667{
668 LOG_REGISTER_CONTEXT;
669
670 FILE *stream = 0;
671 gchar *lsof_command = 0;
672 int count = 0;
673
674 lsof_command = g_strconcat("lsof ", mountpoint, NULL);
675
676 if( (stream = common_popen(lsof_command, "r")) )
677 {
678 char *text = 0;
679 size_t size = 0;
680
681 while( getline(&text, &size, stream) >= 0 )
682 {
683 /* skip the first line as it does not contain process info */
684 if(count != 0)
685 {
686 gchar **split = 0;
687 split = g_strsplit((const gchar*)text, " ", 2);
688 log_err("Mass storage blocked by process %s\n", split[0]);
689 umdbus_send_error_signal(split[0]);
690 g_strfreev(split);
691 }
692 count++;
693 }
694 pclose(stream);
695 free(text);
696 }
697 g_free(lsof_command);
698 if(try == 2)
699 log_err("Setting Mass storage blocked. Giving up.\n");
700
701}
702
703bool modesetting_enter_dynamic_mode(void)
704{
705 LOG_REGISTER_CONTEXT;
706
707 bool ack = false;
708
709 const modedata_t *data;
710
711 log_debug("DYNAMIC MODE: SETUP");
712
713 /* - - - - - - - - - - - - - - - - - - - *
714 * Is a dynamic mode?
715 * - - - - - - - - - - - - - - - - - - - */
716
717 if( !(data = worker_get_usb_mode_data()) ) {
718 log_debug("No dynamic mode data to setup");
719 goto EXIT;
720 }
721
722 log_debug("data->mode_name = %s", data->mode_name);
723 log_debug("data->mass_storage = %d", data->mass_storage);
724#ifdef CONNMAN
725 log_debug("data->connman_tethering = %s", data->connman_tethering ?: "n/a");
726#endif
727 log_debug("data->appsync = %d", data->appsync);
728 log_debug("data->network = %d", data->network);
729 log_debug("data->network_interface = %s%s", data->network_interface,
730 g_strcmp0(data->network_interface, data->cached_interface) ?
731 " (ignored)" : "");
732 log_debug("data->idProduct = %s", data->idProduct ?: "n/a");
733 log_debug("data->idVendorOverride = %s", data->idVendorOverride ?: "n/a");
734 log_debug("data->nat = %d", data->nat);
735 log_debug("data->dhcp_server = %d", data->dhcp_server);
736
737 /* - - - - - - - - - - - - - - - - - - - *
738 * Is a mass storage dynamic mode?
739 * - - - - - - - - - - - - - - - - - - - */
740
741 if( data->mass_storage ) {
742 log_debug("Dynamic mode is mass storage");
743 ack = modesetting_enter_mass_storage_mode(data);
744 goto EXIT;
745 }
746
747 /* - - - - - - - - - - - - - - - - - - - *
748 * Start pre-enum app sync
749 * - - - - - - - - - - - - - - - - - - - */
750
751#ifdef APP_SYNC
752 if( data->appsync ) {
753 log_debug("Dynamic mode is appsync: do pre actions");
754 if( appsync_activate_pre(data->mode_name) != 0 ) {
755 log_debug("Appsync failure");
756 goto EXIT;
757 }
758 }
759#endif
760
761 /* - - - - - - - - - - - - - - - - - - - *
762 * Configure gadget
763 * - - - - - - - - - - - - - - - - - - - */
764
765 if( configfs_in_use() ) {
766 /* Configfs based gadget configuration */
767 configfs_set_function(data->sysfs_value);
768 configfs_set_productid(data->idProduct);
769 char *id = config_get_android_vendor_id();
770 configfs_set_vendorid(data->idVendorOverride ?: id);
771 free(id);
772 if( !configfs_set_udc(true) )
773 goto EXIT;
774 }
775 else if( android_in_use() ) {
776 /* Android USB based gadget configuration */
777 android_set_function(data->sysfs_value);
778 android_set_productid(data->idProduct);
779 char *id = config_get_android_vendor_id();
780 android_set_vendorid(data->idVendorOverride ?: id);
781 free(id);
782 write_to_file(data->android_extra_sysfs_path, data->android_extra_sysfs_value);
783 write_to_file(data->android_extra_sysfs_path2, data->android_extra_sysfs_value2);
784 if( !android_set_enabled(true) )
785 goto EXIT;
786 }
787 else if( modules_in_use() ) {
788 /* Assume relevant module has already been successfully loaded
789 * from somewhere else.
790 */
791 // nop
792 }
793 else {
794 log_crit("no backend is selected, can't set dynamic mode");
795 goto EXIT;
796 }
797
798 /* - - - - - - - - - - - - - - - - - - - *
799 * Setup network
800 * - - - - - - - - - - - - - - - - - - - */
801
802 /* functionality should be enabled, so we can enable the network now */
803 if(data->network)
804 {
805 log_debug("Dynamic mode is network");
806#ifdef DEBIAN
807 char command[256];
808
809 g_snprintf(command, sizeof command, "ifdown %s ; ifup %s", data->cached_interface, data->cached_interface);
810 common_system(command);
811#else
812 network_down(data);
813 int error = network_up(data);
814
815 /* In case of failure, retry upto 3 times */
816 for( int i = 0; error && i < 3; ++i ) {
817 log_warning("Retry setting up the network");
818 if( !common_msleep(1000) )
819 break;
820 if( !(error = network_up(data)) )
821 log_warning("Setting up the network succeeded");
822 }
823 if( error ) {
824 log_err("Setting up the network failed");
825 goto EXIT;
826 }
827#endif /* DEBIAN */
828 }
829
830 /* Needs to be called before application post synching so
831 * that the dhcp server has the right config */
832 if(data->nat || data->dhcp_server) {
833 /* FIXME: The used condition is a bit questionable as dhcpd
834 * service is started based on appsync config - i.e. NOT
835 * based on either nat or setting in modedata ...
836 */
837 if( network_update_udhcpd_config(data) != 0 )
838 goto EXIT;
839 }
840
841 /* - - - - - - - - - - - - - - - - - - - *
842 * Start post-enum app sync
843 * - - - - - - - - - - - - - - - - - - - */
844
845 /* no need to execute the post sync if there was an error setting the mode */
846 if(data->appsync )
847 {
848 log_debug("Dynamic mode is appsync: do post actions");
849 /* let's sleep for a bit (350ms) to allow interfaces to settle before running postsync */
850 common_msleep(350);
852 }
853
854 /* - - - - - - - - - - - - - - - - - - - *
855 * Start tethering
856 * - - - - - - - - - - - - - - - - - - - */
857
858#ifdef CONNMAN
859 if( data->connman_tethering ) {
860 log_debug("Dynamic mode is tethering");
861 if( !connman_set_tethering(data->connman_tethering, true) )
862 goto EXIT;
863 }
864#endif
865
866 ack = true;
867
868EXIT:
869 if( !ack )
870 umdbus_send_error_signal(MODE_SETTING_FAILED);
871 return ack;
872}
873
874void modesetting_leave_dynamic_mode(void)
875{
876 LOG_REGISTER_CONTEXT;
877
878 log_debug("DYNAMIC MODE: CLEANUP");
879
880 const modedata_t *data = worker_get_usb_mode_data();
881
882 /* - - - - - - - - - - - - - - - - - - - *
883 * Is a dynamic mode?
884 * - - - - - - - - - - - - - - - - - - - */
885 if( !data ) {
886 log_debug("No dynamic mode data to cleanup");
887 goto EXIT;
888 }
889
890 log_debug("data->mass_storage = %d", data->mass_storage);
891#ifdef CONNMAN
892 log_debug("data->connman_tethering = %s", data->connman_tethering ?: "n/a");
893#endif
894 log_debug("data->appsync = %d", data->appsync);
895 log_debug("data->network = %d", data->network);
896
897 /* - - - - - - - - - - - - - - - - - - - *
898 * Is a mass storage dynamic mode?
899 * - - - - - - - - - - - - - - - - - - - */
900
901 if( data->mass_storage ) {
902 log_debug("Dynamic mode is mass storage");
903 modesetting_leave_mass_storage_mode(data);
904 goto EXIT;
905 }
906
907 /* - - - - - - - - - - - - - - - - - - - *
908 * Stop tethering
909 * - - - - - - - - - - - - - - - - - - - */
910
911#ifdef CONNMAN
912 if( data->connman_tethering ) {
913 log_debug("Dynamic mode was tethering");
914 connman_set_tethering(data->connman_tethering, false);
915 }
916#endif
917
918 /* - - - - - - - - - - - - - - - - - - - *
919 * Stop post-enum app sync
920 * - - - - - - - - - - - - - - - - - - - */
921
922 if(data->appsync ) {
923 log_debug("Dynamic mode was appsync: undo post actions");
924 /* Just stop post enum appsync apps */
926 }
927
928 /* - - - - - - - - - - - - - - - - - - - *
929 * Teardown network
930 * - - - - - - - - - - - - - - - - - - - */
931
932 if( data->network ) {
933 log_debug("Dynamic mode was network");
934 network_down(data);
935 }
936
937 /* - - - - - - - - - - - - - - - - - - - *
938 * Configure gadget
939 * - - - - - - - - - - - - - - - - - - - */
940
941 if( configfs_in_use() ) {
942 /* Leave as is. We will reprogram wnen mode is
943 * set, not when it is unset.
944 */
945 }
946 else if( android_in_use() ) {
947 /* Leave as is. We will reprogram wnen mode is
948 * set, not when it is unset.
949 */
950 }
951 else if( modules_in_use() ) {
952 /* Assume unloading happens somewhere else */
953 }
954 else {
955 log_crit("no backend is selected, can't unset dynamic mode");
956 }
957
958 /* - - - - - - - - - - - - - - - - - - - *
959 * Stop pre-enum app sync
960 * - - - - - - - - - - - - - - - - - - - */
961
962#ifdef APP_SYNC
963 if( data->appsync ) {
964 log_debug("Dynamic mode was appsync: undo all actions");
965 /* Do full appsync cleanup */
967 }
968#endif
969
970EXIT:
971 return;
972}
973
977{
978 LOG_REGISTER_CONTEXT;
979
980 if( !tracked_values ) {
981 tracked_values = g_hash_table_new_full(g_str_hash, g_str_equal,
982 g_free, g_free);
983 }
984}
985
989{
990 LOG_REGISTER_CONTEXT;
991
992 if( tracked_values ) {
993 g_hash_table_unref(tracked_values), tracked_values = 0;
994 }
995}
gchar * android_extra_sysfs_path
gchar * android_extra_sysfs_value2
gchar * android_extra_sysfs_value
gchar * android_extra_sysfs_path2
bool android_set_attr(const char *function, const char *attr, const char *value)
void appsync_deactivate_all(bool force)
int appsync_activate_post(const char *mode)
void appsync_deactivate_post(void)
int appsync_activate_pre(const char *mode)
void umdbus_send_event_signal(const char *state_ind)
int umdbus_send_error_signal(const char *error)
void modesetting_init(void)
void modesetting_quit(void)
int modules_unload_module(const char *module)
int network_up(const modedata_t *data)
int network_update_udhcpd_config(const modedata_t *data)
void network_down(const modedata_t *data)
const modedata_t * worker_get_usb_mode_data(void)