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