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