usb_moded  0.86.0+mer57
usb_moded-modesetting.c
Go to the documentation of this file.
1 
32 #include "usb_moded-modesetting.h"
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"
39 #include "usb_moded-dbus-private.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 
55 typedef struct storage_info_t
56 {
58  gchar *si_mountpoint;
59 
61  gchar *si_mountdevice;;
63 
64 /* ========================================================================= *
65  * Prototypes
66  * ========================================================================= */
67 
68 /* ------------------------------------------------------------------------- *
69  * MODESETTING
70  * ------------------------------------------------------------------------- */
71 
72 static void modesetting_track_value (const char *path, const char *text);
73 void modesetting_verify_values (void);
74 static char *modesetting_strip (char *str);
75 static char *modesetting_read_from_file (const char *path, size_t maxsize);
76 int modesetting_write_to_file_real (const char *file, int line, const char *func, const char *path, const char *text);
77 bool modesetting_is_mounted (const char *mountpoint);
78 bool modesetting_mount (const char *mountpoint);
79 bool modesetting_unmount (const char *mountpoint);
80 static gchar *modesetting_mountdev (const char *mountpoint);
81 static void modesetting_free_storage_info (storage_info_t *info);
82 static storage_info_t *modesetting_get_storage_info (size_t *pcount);
83 static bool modesetting_enter_mass_storage_mode (const modedata_t *data);
84 static int modesetting_leave_mass_storage_mode (const modedata_t *data);
85 static void modesetting_report_mass_storage_blocker(const char *mountpoint, int try);
86 bool modesetting_enter_dynamic_mode (void);
87 void modesetting_leave_dynamic_mode (void);
88 void modesetting_init (void);
89 void modesetting_quit (void);
90 
91 /* ========================================================================= *
92  * Data
93  * ========================================================================= */
94 
95 static GHashTable *tracked_values = 0;
96 
97 /* ========================================================================= *
98  * Functions
99  * ========================================================================= */
100 
101 static 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 
113 EXIT:
114  return;
115 }
116 
117 void 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 
155 EXIT:
156  return;
157 }
158 
159 static 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 
179 static 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 
210 cleanup:
211  free(data);
212  if(fd != -1) close(fd);
213  return text;
214 }
215 
216 int 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 
289 cleanup:
290 
291  if( fd != -1 ) TEMP_FAILURE_RETRY(close(fd));
292 
293  free(prev);
294  free(repr);
295 
296  return err;
297 }
298 
299 bool 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 
308 bool 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 
317 bool 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 
326 static 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 
344 EXIT:
345  if( fh )
346  endmntent(fh);
347 
348  log_debug("%s -> %s", mountpoint, res);
349 
350  return res;
351 }
352 
353 static void
354 modesetting_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 
367 static storage_info_t *
368 modesetting_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 
420 EXIT:
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 
430 static 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 
552 EXIT:
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 
568 static 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 
655 EXIT:
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 
665 static 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 
702 bool 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 
865 EXIT:
866  if( !ack )
867  umdbus_send_error_signal(MODE_SETTING_FAILED);
868  return ack;
869 }
870 
871 void 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 */
963  appsync_deactivate_all(false);
964  }
965 #endif
966 
967 EXIT:
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 }
modedata_t::mode_name
gchar * mode_name
Definition: usb_moded-dyn-config.h:102
umdbus_send_error_signal
int umdbus_send_error_signal(const char *error)
Definition: usb_moded-dbus.c:1818
modedata_t::nat
int nat
Definition: usb_moded-dyn-config.h:121
usb_moded-dbus-private.h
usb_moded-modules.h
modedata_t::network_interface
gchar * network_interface
Definition: usb_moded-dyn-config.h:107
appsync_activate_post
int appsync_activate_post(const char *mode)
Definition: usb_moded-appsync.c:562
usb_moded-modesetting.h
modedata_t::network
int network
Definition: usb_moded-dyn-config.h:105
network_up
int network_up(const modedata_t *data)
Definition: usb_moded-network.c:1114
usb_moded-configfs.h
usb_moded-android.h
modedata_t::mass_storage
int mass_storage
Definition: usb_moded-dyn-config.h:106
usb_moded-network.h
modedata_t::appsync
int appsync
Definition: usb_moded-dyn-config.h:104
usb_moded-config-private.h
modedata_t::android_extra_sysfs_path
gchar * android_extra_sysfs_path
Definition: usb_moded-dyn-config.h:111
modedata_t::dhcp_server
int dhcp_server
Definition: usb_moded-dyn-config.h:122
appsync_activate_pre
int appsync_activate_pre(const char *mode)
Definition: usb_moded-appsync.c:430
modedata_t::android_extra_sysfs_value
gchar * android_extra_sysfs_value
Definition: usb_moded-dyn-config.h:112
modedata_t::android_extra_sysfs_path2
gchar * android_extra_sysfs_path2
Definition: usb_moded-dyn-config.h:113
modules_unload_module
int modules_unload_module(const char *module)
Definition: usb_moded-modules.c:253
appsync_deactivate_all
void appsync_deactivate_all(bool force)
Definition: usb_moded-appsync.c:842
usb_moded-appsync.h
umdbus_send_event_signal
void umdbus_send_event_signal(const char *state_ind)
Definition: usb_moded-dbus.c:1802
storage_info_t
struct storage_info_t storage_info_t
modedata_t::idProduct
gchar * idProduct
Definition: usb_moded-dyn-config.h:119
android_set_attr
bool android_set_attr(const char *function, const char *attr, const char *value)
Definition: usb_moded-android.c:372
network_update_udhcpd_config
int network_update_udhcpd_config(const modedata_t *data)
Definition: usb_moded-network.c:1059
modesetting_init
void modesetting_init(void)
Definition: usb_moded-modesetting.c:973
modedata_t::sysfs_value
gchar * sysfs_value
Definition: usb_moded-dyn-config.h:109
modedata_t::idVendorOverride
gchar * idVendorOverride
Definition: usb_moded-dyn-config.h:120
modesetting_quit
void modesetting_quit(void)
Definition: usb_moded-modesetting.c:985
network_down
void network_down(const modedata_t *data)
Definition: usb_moded-network.c:1194
storage_info_t::si_mountpoint
gchar * si_mountpoint
Definition: usb_moded-modesetting.c:58
appsync_deactivate_post
void appsync_deactivate_post(void)
Definition: usb_moded-appsync.c:824
usb_moded-common.h
usb_moded-log.h
modedata_t
Definition: usb_moded-dyn-config.h:100
storage_info_t
Definition: usb_moded-modesetting.c:55
storage_info_t::si_mountdevice
gchar * si_mountdevice
Definition: usb_moded-modesetting.c:61
modedata_t::android_extra_sysfs_value2
gchar * android_extra_sysfs_value2
Definition: usb_moded-dyn-config.h:114
usb_moded-worker.h
worker_get_usb_mode_data
const modedata_t * worker_get_usb_mode_data(void)
Definition: usb_moded-worker.c:541