diff options
-rw-r--r-- | android/avd/hardware-properties.ini | 22 | ||||
-rw-r--r-- | android/avd/hw-config-defs.h | 23 | ||||
-rw-r--r-- | android/avd/info.c | 65 | ||||
-rw-r--r-- | android/avd/info.h | 6 | ||||
-rw-r--r-- | android/main-common.c | 67 | ||||
-rw-r--r-- | android/main-common.h | 2 | ||||
-rw-r--r-- | android/main-ui.c | 55 | ||||
-rw-r--r-- | android/main.c | 59 | ||||
-rw-r--r-- | android/qemulator.c | 2 | ||||
-rw-r--r-- | android/qemulator.h | 4 | ||||
-rw-r--r-- | qemu-options.hx | 93 | ||||
-rw-r--r-- | slirp-android/libslirp.h | 57 | ||||
-rw-r--r-- | slirp-android/slirp.c | 302 | ||||
-rw-r--r-- | slirp-android/socket.c | 21 | ||||
-rw-r--r-- | slirp-android/tcp_subr.c | 169 | ||||
-rw-r--r-- | slirp-android/udp.c | 51 | ||||
-rw-r--r-- | slirp-android/udp.h | 4 | ||||
-rw-r--r-- | vl-android.c | 362 |
18 files changed, 1150 insertions, 214 deletions
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini index 6b106f4..89acf9f 100644 --- a/android/avd/hardware-properties.ini +++ b/android/avd/hardware-properties.ini @@ -24,6 +24,8 @@ # # Ram size +# Default value will be computed based on screen pixels +# or skin version name = hw.ramSize type = integer default = 0 @@ -146,6 +148,23 @@ type = diskSize abstract = Cache partition size default = 66MB +# LCD width +name = hw.lcd.width +type = integer +default = 320 +abstract = LCD pixel width + +name = hw.lcd.height +type = integer +default = 640 +abstract = LCD pixel height + +name = hw.lcd.depth +type = integer +default = 16 +abstract = LCD color depth +description = Must be 16 or 32. Color bit depth of emulated framebuffer. + # LCD density name = hw.lcd.density type = integer @@ -155,9 +174,10 @@ description = Must be one of 120, 160 or 240. A value used to roughly describe t # Maximum VM heap size # Higher values are required for high-dpi devices +# Default will depend on RAM size. name = vm.heapSize type = integer -default = 16 +default = 0 abstract = Max VM application heap size description = The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes. diff --git a/android/avd/hw-config-defs.h b/android/avd/hw-config-defs.h index 0c87bdb..4afc4d7 100644 --- a/android/avd/hw-config-defs.h +++ b/android/avd/hw-config-defs.h @@ -144,6 +144,27 @@ HWCFG_DISKSIZE( "") HWCFG_INT( + hw_lcd_width, + "hw.lcd.width", + 320, + "LCD pixel width", + "") + +HWCFG_INT( + hw_lcd_height, + "hw.lcd.height", + 640, + "LCD pixel height", + "") + +HWCFG_INT( + hw_lcd_depth, + "hw.lcd.depth", + 16, + "LCD color depth", + "Must be 16 or 32. Color bit depth of emulated framebuffer.") + +HWCFG_INT( hw_lcd_density, "hw.lcd.density", 160, @@ -153,7 +174,7 @@ HWCFG_INT( HWCFG_INT( vm_heapSize, "vm.heapSize", - 16, + 0, "Max VM application heap size", "The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes.") diff --git a/android/avd/info.c b/android/avd/info.c index 058226c..e3d38bb 100644 --- a/android/avd/info.c +++ b/android/avd/info.c @@ -93,6 +93,12 @@ AvdInfo* android_avdInfo; */ #define SDCARD_PATH "sdcard.path" +/* the name of the .ini file that will contain the complete hardware + * properties for the AVD. This will be used to launch the corresponding + * core from the UI. + */ +#define CORE_HARDWARE_INI "qemu-hardware.ini" + /* certain disk image files are mounted read/write by the emulator * to ensure that several emulators referencing the same files * do not corrupt these files, we need to lock them and respond @@ -134,11 +140,12 @@ struct AvdInfo { char* contentPath; IniFile* rootIni; /* root <foo>.ini file */ IniFile* configIni; /* virtual device's config.ini */ - IniFile* hardwareIni; /* skin-specific hardware.ini */ + IniFile* skinHardwareIni; /* skin-specific hardware.ini */ /* for both */ char* skinName; /* skin name */ char* skinDirPath; /* skin directory */ + char* coreHardwareIniPath; /* core hardware.ini path */ /* image files */ char* imagePath [ AVD_IMAGE_MAX ]; @@ -157,6 +164,7 @@ avdInfo_free( AvdInfo* i ) AFREE(i->skinName); AFREE(i->skinDirPath); + AFREE(i->coreHardwareIniPath); for (nn = 0; nn < i->numSearchPaths; nn++) AFREE(i->searchPaths[nn]); @@ -168,9 +176,9 @@ avdInfo_free( AvdInfo* i ) i->configIni = NULL; } - if (i->hardwareIni) { - iniFile_free(i->hardwareIni); - i->hardwareIni = NULL; + if (i->skinHardwareIni) { + iniFile_free(i->skinHardwareIni); + i->skinHardwareIni = NULL; } if (i->rootIni) { @@ -558,7 +566,7 @@ imageLoader_empty( ImageLoader* l, unsigned flags ) } -/* copy image file from a given source +/* copy image file from a given source * assumes locking is needed. */ static void @@ -606,7 +614,7 @@ imageLoader_load( ImageLoader* l, /* set image state */ l->pState[0] = (flags & IMAGE_DONT_LOCK) == 0 - ? IMAGE_STATE_MUSTLOCK + ? IMAGE_STATE_MUSTLOCK : IMAGE_STATE_READONLY; /* check user-provided path */ @@ -651,7 +659,7 @@ imageLoader_load( ImageLoader* l, if (flags & IMAGE_REQUIRED) { AvdInfo* i = l->info; - derror("could not find required %s image (%s).", + derror("could not find required %s image (%s).", l->imageText, l->imageFile); if (i->inAndroidBuild) { @@ -1088,6 +1096,22 @@ _getSDCardPath( AvdInfo* i, AvdInfoParams* params ) params->forcePaths[AVD_IMAGE_SDCARD] = path; } +static int +_getCoreHwIniPath( AvdInfo* i, const char* basePath ) +{ + char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); + + p = bufprint(temp, end, "%s/%s", basePath, CORE_HARDWARE_INI); + if (p >= end) { + DD("Path too long for %s:", CORE_HARDWARE_INI, basePath); + return -1; + } + + D("using core hw config path: %s", temp); + i->coreHardwareIniPath = ASTRDUP(temp); + return 0; +} + AvdInfo* avdInfo_new( const char* name, AvdInfoParams* params ) { @@ -1107,7 +1131,8 @@ avdInfo_new( const char* name, AvdInfoParams* params ) if ( _getSdkRoot(i) < 0 || _getRootIni(i) < 0 || _getContentPath(i) < 0 || - _getConfigIni(i) < 0 ) + _getConfigIni(i) < 0 || + _getCoreHwIniPath(i, i->contentPath) < 0 ) goto FAIL; /* look for image search paths. handle post 1.1/pre cupcake @@ -1280,7 +1305,7 @@ _getBuildImagePaths( AvdInfo* i, AvdInfoParams* params ) /* if the user provided one cache image, lock & use it */ if ( params->forcePaths[l->id] != NULL ) { - imageLoader_load(l, IMAGE_REQUIRED | + imageLoader_load(l, IMAGE_REQUIRED | IMAGE_IGNORE_IF_LOCKED); } } @@ -1373,7 +1398,7 @@ _getBuildSkin( AvdInfo* i, AvdInfoParams* params ) /* Read a hardware.ini if it is located in the skin directory */ static int -_getBuildHardwareIni( AvdInfo* i ) +_getBuildSkinHardwareIni( AvdInfo* i ) { char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); @@ -1387,14 +1412,13 @@ _getBuildHardwareIni( AvdInfo* i ) } D("found skin-specific hardware.ini: %s", temp); - i->hardwareIni = iniFile_newFromFile(temp); - if (i->hardwareIni == NULL) + i->skinHardwareIni = iniFile_newFromFile(temp); + if (i->skinHardwareIni == NULL) return -1; return 0; } - AvdInfo* avdInfo_newForAndroidBuild( const char* androidBuildRoot, const char* androidOut, @@ -1413,12 +1437,13 @@ avdInfo_newForAndroidBuild( const char* androidBuildRoot, i->deviceName = ASTRDUP("<build>"); if (_getBuildConfigIni(i) < 0 || - _getBuildImagePaths(i, params) < 0 ) + _getBuildImagePaths(i, params) < 0 || + _getCoreHwIniPath(i, i->androidOut) < 0 ) goto FAIL; /* we don't need to fail if there is no valid skin */ _getBuildSkin(i, params); - _getBuildHardwareIni(i); + _getBuildSkinHardwareIni(i); return i; @@ -1492,8 +1517,8 @@ avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw ) if (ini != i->configIni) iniFile_free(ini); - if (ret == 0 && i->hardwareIni != NULL) { - ret = androidHwConfig_read(hw, i->hardwareIni); + if (ret == 0 && i->skinHardwareIni != NULL) { + ret = androidHwConfig_read(hw, i->skinHardwareIni); } /* special product-specific hardware configuration */ @@ -1539,3 +1564,9 @@ avdInfo_getTracePath( AvdInfo* i, const char* traceName ) } return ASTRDUP(tmp); } + +const char* +avdInfo_getCoreHwIniPath( AvdInfo* i ) +{ + return i->coreHardwareIniPath; +} diff --git a/android/avd/info.h b/android/avd/info.h index 2b2899f..9ccee30 100644 --- a/android/avd/info.h +++ b/android/avd/info.h @@ -183,6 +183,12 @@ int avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw ); /* Returns a *copy* of the path used to store trace 'foo'. result must be freed by caller */ char* avdInfo_getTracePath( AvdInfo* i, const char* traceName ); +/* Returns the path of the hardware.ini where we will write the AVD's + * complete hardware configuration before launching the corresponding + * core. + */ +const char* avdInfo_getCoreHwIniPath( AvdInfo* i ); + /* */ #endif /* ANDROID_AVD_INFO_H */ diff --git a/android/main-common.c b/android/main-common.c index bb07943..a63983b 100644 --- a/android/main-common.c +++ b/android/main-common.c @@ -341,6 +341,7 @@ void parse_skin_files(const char* skinDirPath, const char* skinName, AndroidOptions* opts, + AndroidHwConfig* hwConfig, AConfig* *skinConfig, char* *skinPath) { @@ -433,6 +434,53 @@ FOUND_SKIN: skin_network_delay = aconfig_str(n, "delay", 0); } + /* extract framebuffer information from the skin. + * + * for version 1 of the skin format, they are in the top-level + * 'display' element. + * + * for version 2 of the skin format, they are under parts.device.display + */ + n = aconfig_find(root, "display"); + if (n == NULL) { + n = aconfig_find(root, "parts"); + if (n != NULL) { + n = aconfig_find(root, "device"); + if (n != NULL) { + n = aconfig_find(root, "display"); + } + } + } + + if (n != NULL) { + int width = aconfig_int(n, "width", hwConfig->hw_lcd_width); + int height = aconfig_int(n, "height", hwConfig->hw_lcd_height); + int depth = aconfig_int(n, "bpp", hwConfig->hw_lcd_depth); + + if (width > 0 && height > 0) { + /* The emulated framebuffer wants sizes that are multiples of 4 */ + if (((width|height) & 3) != 0) { + width = (width+3) & ~3; + height = (height+3) & ~3; + D("adjusting LCD dimensions to (%dx%dx)", width, height); + } + + /* only depth values of 16 and 32 are correct. 16 is the default. */ + if (depth != 32 && depth != 16) { + depth = 16; + D("adjusting LCD bit depth to %d", depth); + } + + hwConfig->hw_lcd_width = width; + hwConfig->hw_lcd_height = height; + hwConfig->hw_lcd_depth = depth; + } + else { + D("ignoring invalid skin LCD dimensions (%dx%dx%d)", + width, height, depth); + } + } + *skinConfig = root; *skinPath = strdup(path); return; @@ -536,22 +584,3 @@ init_sdl_ui(AConfig* skinConfig, qemulator_get()->onion_rotation = rotate; } } - -int64_t get_screen_pixels(AConfig* skinConfig) -{ - int64_t pixels = 0; - AConfig* disp; - - if (skinConfig != NULL) { - disp = aconfig_find(skinConfig, "display"); - if (disp != NULL) { - int width = aconfig_int(disp, "width", 0); - int height = aconfig_int(disp, "height", 0); - pixels = (int64_t)width*height; - } - } - if (pixels == 0) - pixels = 320*240; - - return pixels; -} diff --git a/android/main-common.h b/android/main-common.h index c5131df..88ebb70 100644 --- a/android/main-common.h +++ b/android/main-common.h @@ -16,6 +16,7 @@ #include "android/cmdline-option.h" #include "android/skin/keyset.h" #include "android/config.h" +#include "android/avd/hw-config.h" /* Common routines used by both android/main.c and android/main-ui.c */ @@ -45,6 +46,7 @@ extern const char* skin_network_delay; void parse_skin_files(const char* skinDirPath, const char* skinName, AndroidOptions* opts, + AndroidHwConfig* hwConfig, AConfig* *skinConfig, char* *skinPath); diff --git a/android/main-ui.c b/android/main-ui.c index 273f402..f1f8539 100644 --- a/android/main-ui.c +++ b/android/main-ui.c @@ -490,8 +490,6 @@ int main(int argc, char **argv) char* android_build_out = NULL; AndroidOptions opts[1]; - /* LCD density value to pass to the core. */ - char lcd_density[16]; /* net.shared_net_ip boot property value. */ char boot_prop_ip[64]; boot_prop_ip[0] = '\0'; @@ -876,7 +874,7 @@ int main(int argc, char **argv) user_config_init(); - parse_skin_files(opts->skindir, opts->skin, opts, + parse_skin_files(opts->skindir, opts->skin, opts, hw, &skinConfig, &skinPath); if (!opts->netspeed) { @@ -1257,6 +1255,7 @@ int main(int argc, char **argv) derror( "physical memory size must be between 32 and 4096 MB" ); exit(1); } + hw->hw_ramSize = ramSize; } if (!opts->memory) { int ramSize = hw->hw_ramSize; @@ -1266,8 +1265,7 @@ int main(int argc, char **argv) * size through its hardware.ini (i.e. legacy ones) or when * in the full Android build system. */ - int64_t pixels = get_screen_pixels(skinConfig); - + int64_t pixels = hw->hw_lcd_width * hw->hw_lcd_height; /* The following thresholds are a bit liberal, but we * essentially want to ensure the following mappings: * @@ -1285,8 +1283,30 @@ int main(int argc, char **argv) else ramSize = 256; } - bufprint(tmp, tmpend, "%d", ramSize); - opts->memory = android_strdup(tmp); + hw->hw_ramSize = ramSize; + } + + D("Physical RAM size: %dMB\n", hw->hw_ramSize); + + if (hw->vm_heapSize == 0) { + /* Compute the default heap size based on the RAM size. + * Essentially, we want to ensure the following liberal mappings: + * + * 96MB RAM -> 16MB heap + * 128MB RAM -> 24MB heap + * 256MB RAM -> 48MB heap + */ + int ramSize = hw->hw_ramSize; + int heapSize; + + if (ramSize < 100) + heapSize = 16; + else if (ramSize < 192) + heapSize = 24; + else + heapSize = 48; + + hw->vm_heapSize = heapSize; } if (opts->trace) { @@ -1296,11 +1316,6 @@ int main(int argc, char **argv) args[n++] = "off"; } - /* Pass LCD density value to the core. */ - snprintf(lcd_density, sizeof(lcd_density), "%d", hw->hw_lcd_density); - args[n++] = "-lcd-density"; - args[n++] = lcd_density; - /* Pass boot properties to the core. */ if (opts->prop != NULL) { ParamList* pl = opts->prop; @@ -1465,21 +1480,15 @@ int main(int argc, char **argv) * launch the core with the -android-hw <file> option. */ { - TempFile* tempHw = tempfile_create(); - if (tempHw == NULL) { - derror("Could not create temporary hardware.ini: %s", strerror(errno)); - exit(2); - } - - const char* tempHwPath = tempfile_path(tempHw); - IniFile* hwIni = iniFile_newFromMemory("", NULL); + const char* coreHwIniPath = avdInfo_getCoreHwIniPath(avd); + IniFile* hwIni = iniFile_newFromMemory("", NULL); androidHwConfig_write(hw, hwIni); - if (iniFile_saveToFile(hwIni, tempHwPath) < 0) { - derror("Could not write temporary hardware.ini: %s", tempHwPath); + if (iniFile_saveToFile(hwIni, coreHwIniPath) < 0) { + derror("Could not write hardware.ini to %s: %s", coreHwIniPath, strerror(errno)); exit(2); } args[n++] = "-android-hw"; - args[n++] = strdup(tempHwPath); + args[n++] = strdup(coreHwIniPath); } if(VERBOSE_CHECK(init)) { diff --git a/android/main.c b/android/main.c index 51ef6d7..7a228f0 100644 --- a/android/main.c +++ b/android/main.c @@ -298,8 +298,6 @@ int main(int argc, char **argv) char* android_build_out = NULL; AndroidOptions opts[1]; - /* LCD density value to pass to the core. */ - char lcd_density[16]; /* net.shared_net_ip boot property value. */ char boot_prop_ip[64]; boot_prop_ip[0] = '\0'; @@ -667,7 +665,7 @@ int main(int argc, char **argv) user_config_init(); - parse_skin_files(opts->skindir, opts->skin, opts, + parse_skin_files(opts->skindir, opts->skin, opts, hw, &skinConfig, &skinPath); if (!opts->netspeed) { @@ -1050,6 +1048,7 @@ int main(int argc, char **argv) derror( "physical memory size must be between 32 and 4096 MB" ); exit(1); } + hw->hw_ramSize = ramSize; } if (!opts->memory) { int ramSize = hw->hw_ramSize; @@ -1059,8 +1058,7 @@ int main(int argc, char **argv) * size through its hardware.ini (i.e. legacy ones) or when * in the full Android build system. */ - int64_t pixels = get_screen_pixels(skinConfig); - + int64_t pixels = hw->hw_lcd_width * hw->hw_lcd_height; /* The following thresholds are a bit liberal, but we * essentially want to ensure the following mappings: * @@ -1078,8 +1076,30 @@ int main(int argc, char **argv) else ramSize = 256; } - bufprint(tmp, tmpend, "%d", ramSize); - opts->memory = android_strdup(tmp); + hw->hw_ramSize = ramSize; + } + + D("Physical RAM size: %dMB\n", hw->hw_ramSize); + + if (hw->vm_heapSize == 0) { + /* Compute the default heap size based on the RAM size. + * Essentially, we want to ensure the following liberal mappings: + * + * 96MB RAM -> 16MB heap + * 128MB RAM -> 24MB heap + * 256MB RAM -> 48MB heap + */ + int ramSize = hw->hw_ramSize; + int heapSize; + + if (ramSize < 100) + heapSize = 16; + else if (ramSize < 192) + heapSize = 24; + else + heapSize = 48; + + hw->vm_heapSize = heapSize; } if (opts->trace) { @@ -1089,11 +1109,6 @@ int main(int argc, char **argv) args[n++] = "off"; } - /* Pass LCD density value to the core. */ - snprintf(lcd_density, sizeof(lcd_density), "%d", get_device_dpi(opts)); - args[n++] = "-lcd-density"; - args[n++] = lcd_density; - /* Pass boot properties to the core. */ if (opts->prop != NULL) { ParamList* pl = opts->prop; @@ -1216,9 +1231,7 @@ int main(int argc, char **argv) args[n++] = opts->memcheck; } - /* physical memory */ - args[n++] = "-m"; - args[n++] = opts->memory; + /* physical memory is now in hw->hw_ramSize */ /* on Linux, the 'dynticks' clock sometimes doesn't work * properly. this results in the UI freezing while emulation @@ -1262,21 +1275,15 @@ int main(int argc, char **argv) * launch the core with the -android-hw <file> option. */ { - TempFile* tempHw = tempfile_create(); - if (tempHw == NULL) { - derror("Could not create temporary hardware.ini: %s", strerror(errno)); - exit(2); - } - - const char* tempHwPath = tempfile_path(tempHw); - IniFile* hwIni = iniFile_newFromMemory("", NULL); + const char* coreHwIniPath = avdInfo_getCoreHwIniPath(avd); + IniFile* hwIni = iniFile_newFromMemory("", NULL); androidHwConfig_write(hw, hwIni); - if (iniFile_saveToFile(hwIni, tempHwPath) < 0) { - derror("Could not write temporary hardware.ini: %s", tempHwPath); + if (iniFile_saveToFile(hwIni, coreHwIniPath) < 0) { + derror("Could not write hardware.ini to %s: %s", coreHwIniPath, strerror(errno)); exit(2); } args[n++] = "-android-hw"; - args[n++] = strdup(tempHwPath); + args[n++] = strdup(coreHwIniPath); } if(VERBOSE_CHECK(init)) { diff --git a/android/qemulator.c b/android/qemulator.c index ee9ccbb..b15d751 100644 --- a/android/qemulator.c +++ b/android/qemulator.c @@ -258,7 +258,7 @@ qemulator_set_title(QEmulator* emulator) * Helper routines */ -int +static int get_device_dpi( AndroidOptions* opts ) { int dpi_device = corecmd_get_hw_lcd_density(); diff --git a/android/qemulator.h b/android/qemulator.h index 189cc53..bd77ae1 100644 --- a/android/qemulator.h +++ b/android/qemulator.h @@ -66,8 +66,4 @@ qemulator_get_layout( QEmulator* emulator ); QFrameBuffer* qemulator_get_first_framebuffer(QEmulator* emulator); -/* A helper routine for getting device DPI. */ -int -get_device_dpi( AndroidOptions* opts ); - #endif // QEMU_ANDROID_QEMULATOR_H diff --git a/qemu-options.hx b/qemu-options.hx index baae81b..80efaa6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1440,6 +1440,95 @@ Set the initial date of the real time clock. Valid formats for @code{2006-06-17}. The default value is @code{now}. ETEXI +/* Start user mode network stack restrictions */ +DEF("drop-udp", 0, QEMU_OPTION_drop_udp, \ + "-drop-udp starts filtering all UDP packets\n") +STEXI + +@item -drop-udp +Enable dropping of all UDP packets. +ETEXI + + +DEF("drop-tcp", 0, QEMU_OPTION_drop_tcp, \ + "-drop-tcp starts filtering all TCP packets\n") +STEXI + +@item -drop-tcp +Enable dropping of all TCP packets. +ETEXI + + +DEF("allow-tcp", HAS_ARG, QEMU_OPTION_allow_tcp, \ + "-allow-tcp Only allows TCP packets for host:port\n") +STEXI + +@item -allow-tcp @var{host}:@var{port} +Allows communication with the host named @code{host} and with +the port @code{port}. +ETEXI + + +DEF("drop-log", 0, QEMU_OPTION_drop_log, \ + "-drop-log Creates a log for dropped connections\n") +STEXI + +@item -drop-log @var{file} +Creates a log for dropped connections in the file @code{file}. +ETEXI + +/* Additional network restriction options */ + +DEF("max-dns-conns", HAS_ARG, QEMU_OPTION_max_dns_conns, \ + "-max-dns-conns limit \n" + " Limits the maximum DNS connections\n") +STEXI +@item -max-dns-conns @var{limit} +Limits the maximum DNS connections to @var{limit}. +ETEXI + +DEF("allow-udp", HAS_ARG, QEMU_OPTION_allow_udp, \ + "-allow-udp host:port \n" + " Allows udp connections to go through to host:port\n") +STEXI +@item -allow-udp @var{host}:@var{port} +Allows udp connections to go through to @var{host}:@var{port}. +ETEXI + +DEF("dns-log", HAS_ARG, QEMU_OPTION_dns_log, \ + "-dns-log file Creates a log of DNS lookups\n") +STEXI +@item -dns-log @var{file} +Creates a log of DNS lookups as @var{file}. +ETEXI + + +DEF("net-forward", HAS_ARG, QEMU_OPTION_net_forward, \ +"-net-forward dst_net:dst_mask:dst_port:redirect_ip:redirect_port:\n" +" Forwards guest network traffic sent to dst_net(dst_mask):dst_port\n" +" to redirect_ip:redirect_port\n") + +STEXI +@item -net-forward @var{settings} +Forwards network traffic using the settings @code{settings}. +ETEXI + + +DEF("net-forward-tcp2sink", HAS_ARG, QEMU_OPTION_net_forward_tcp2sink, \ +"-net-forward-tcp2sink sink_ip:sink_port\n" +" Forwards all dropped and non-forwarded guest network traffic\n" +" to specified ip:port. \n") + +STEXI +@item -net-forward-tcp2sink @var{settings} +Forwards all dropped and non-forwarded network traffic to sink ip:port. +ETEXI + + + +/* End User mode network stack restrictions */ + + DEF("icount", HAS_ARG, QEMU_OPTION_icount, \ "-icount [N|auto]\n" \ " enable virtual instruction counter with 2^N clock ticks per\n" \ @@ -1631,10 +1720,6 @@ DEF("charmap", HAS_ARG, QEMU_OPTION_charmap, \ "-charmap <file>" " use specific key character map\n") -DEF("android-gui", HAS_ARG, QEMU_OPTION_android_gui, \ - "-android-gui width=<width>,height=<height>,bpp=<bits per pixel>" - " width, height, and bits per pixel for the graphic console\n") - DEF("android-hw", HAS_ARG, QEMU_OPTION_android_hw, \ "-android-hw <file> read hardware initialization from ini file\n") diff --git a/slirp-android/libslirp.h b/slirp-android/libslirp.h index 6086384..120e3d3 100644 --- a/slirp-android/libslirp.h +++ b/slirp-android/libslirp.h @@ -2,7 +2,9 @@ #define _LIBSLIRP_H #include <stdint.h> +#include <stdio.h> #include "sockets.h" +#include "slirp.h" #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # define socket_close winsock2_socket_close3 @@ -16,6 +18,8 @@ extern "C" { #endif +struct mbuf; + int inet_strtoip(const char* str, uint32_t *ip); char* inet_iptostr(uint32_t ip); @@ -32,6 +36,59 @@ void slirp_input(const uint8_t *pkt, int pkt_len); int slirp_can_output(void); void slirp_output(const uint8_t *pkt, int pkt_len); +/* ---------------------------------------------------*/ +/* User mode network stack restrictions */ +void slirp_drop_udp(); +void slirp_drop_tcp(); +void slirp_add_allow(unsigned long dst_addr, int dst_lport, + int dst_hport, u_int8_t proto); +void slirp_drop_log_fd(FILE* fd); +int slirp_should_drop(unsigned long dst_addr, + int dst_port, + u_int8_t proto); +int slirp_drop_log(const char* format, ...); + +/* for network forwards */ +void slirp_add_net_forward(unsigned long dest_ip, unsigned long dest_mask, + int dest_lport, int dest_hport, + unsigned long redirect_ip, int redirect_port); + +int slirp_should_net_forward(unsigned long remote_ip, int remote_port, + unsigned long *redirect_ip, int *redirect_port); +/* ---------------------------------------------------*/ + +/** + * Additional network stack modifications, aiming to detect and log + * any network activity initiated by any binary outisde the context of + * the running browser. + */ + +void slirp_dns_log_fd(FILE* fd); +/** Logs the DNS name in DNS query issued by the VM. */ +int slirp_log_dns(struct mbuf* m, int dropped); +/** IP packet dump of DNS queris and responses. */ +int slirp_dump_dns(struct mbuf* m); +/** Sets an upper limit for the number of allowed DNS requests from + * the VM. + */ +void slirp_set_max_dns_conns(int max_dns_conns); +/* Returns the max number of allowed DNS requests.*/ +int slirp_get_max_dns_conns(); + +/** + * Modifications for implementing "-net-forward-tcp2sink' option. + */ + +void slirp_forward_dropped_tcp2sink(unsigned long sink_ip, int sink_port); +int slirp_should_forward_dropped_tcp2sink(); +unsigned long slirp_get_tcp_sink_ip(); +int slirp_get_tcp_sink_port(); + + + + +/* ---------------------------------------------------*/ + void slirp_redir_loop(void (*func)(void *opaque, int is_udp, const SockAddress *laddr, const SockAddress *faddr), diff --git a/slirp-android/slirp.c b/slirp-android/slirp.c index dc94a99..015918f 100644 --- a/slirp-android/slirp.c +++ b/slirp-android/slirp.c @@ -32,6 +32,12 @@ #include "android/android.h" #include "sockets.h" +#include "qemu-queue.h" + +/* proto types */ +static void slirp_net_forward_init(void); + + #define D(...) VERBOSE_PRINT(slirp,__VA_ARGS__) #define DN(...) do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0) @@ -81,7 +87,7 @@ int slirp_add_dns_server(const SockAddress* new_dns_addr) return -1; dns_ip = sock_address_get_ip(new_dns_addr); - if (dns_ip < 0) + if (dns_ip == -1) return -1; dns_addr[dns_addr_count++] = dns_ip; @@ -259,6 +265,8 @@ void slirp_init(int restricted, const char *special_ip) alias_addr_ip = special_addr_ip | CTL_ALIAS; getouraddr(); register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL); + + slirp_net_forward_init(); } #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) @@ -819,6 +827,298 @@ void if_encap(const uint8_t *ip_data, int ip_data_len) } } + +/*---------------------------------------------------*/ +/* User mode network stack restrictions */ +struct fw_allow_entry { + struct fw_allow_entry* next; + unsigned long dst_addr; /* host byte order */ + /* Allowed port range. dst_lport should be the same as dst_hport for a + * single port. */ + unsigned short dst_lport; /* host byte order */ + unsigned short dst_hport; /* host byte order */ +}; + +static int drop_udp = 0; +static int drop_tcp = 0; +static struct fw_allow_entry* allow_tcp_entries = NULL; +static struct fw_allow_entry* allow_udp_entries = NULL; +static FILE* drop_log_fd = NULL; +static FILE* dns_log_fd = NULL; +static int max_dns_conns = -1; /* unlimited max DNS connections by default */ +static int slirp_net_forward_inited = 0; + +void slirp_drop_udp() { + drop_udp = 1; +} + +void slirp_drop_tcp() { + drop_tcp = 1; +} + +/* TCP traffic forwarding to a sink - If enabled, all TCP traffic to any + * ip/port that is not explicitly forwared using '-net-forward', and which would + * otherwise be dropped if '-drop-tcp' has been specified, is redirected to the + * specified ip:port + */ +int forward_dropped_tcp2sink = 0; +static unsigned long tcp_sink_ip; +int tcp_sink_port; + +void slirp_forward_dropped_tcp2sink(unsigned long sink_ip, int sink_port) { + tcp_sink_ip = sink_ip; + tcp_sink_port = sink_port; + forward_dropped_tcp2sink = 1; +} + +int slirp_should_forward_dropped_tcp2sink() { + return forward_dropped_tcp2sink; +} + +unsigned long slirp_get_tcp_sink_ip() { + return tcp_sink_ip; +} +int slirp_get_tcp_sink_port() { + return tcp_sink_port; +} + +/* Fill in the firewall rules. dst_lport and dst_hport are in host byte order */ +void slirp_add_allow(unsigned long dst_addr, + int dst_lport, int dst_hport, + u_int8_t proto) { + + struct fw_allow_entry** ate; + switch (proto) { + case IPPROTO_TCP: + ate = &allow_tcp_entries; + break; + case IPPROTO_UDP: + ate = &allow_udp_entries; + break; + default: + return; // unknown protocol for the FW + } + + while(*ate != NULL) + ate = &(*ate)->next; + + *ate = malloc(sizeof(**ate)); + if (*ate == NULL) { + DEBUG_MISC((dfd, + "Unable to create new firewall record, malloc failed\n")); + exit(-1); + } + + (*ate)->next = NULL; + (*ate)->dst_addr = dst_addr; + (*ate)->dst_lport = dst_lport; + (*ate)->dst_hport = dst_hport; +} + +void slirp_drop_log_fd(FILE* fd) { + drop_log_fd = fd; +} + +void slirp_dns_log_fd(FILE* fd) { + dns_log_fd = fd; +} + +/* Address and ports are in host byte order */ +int slirp_should_drop(unsigned long dst_addr, + int dst_port, + u_int8_t proto) { + + struct fw_allow_entry* ate; + + switch (proto) { + case IPPROTO_TCP: + if (drop_tcp != 0) + ate = allow_tcp_entries; + else + return 0; + break; + case IPPROTO_UDP: + if (drop_udp != 0) + ate = allow_udp_entries; + else + return 0; + break; + default: + return 1; // unknown protocol for the FW + } + + while(ate) { + if ((ate->dst_lport <= dst_port) && (dst_port <= ate->dst_hport)) { + // allow any destination if 0 + if (ate->dst_addr == 0 || ate->dst_addr == dst_addr) + return 0; + } + ate = ate->next; + } + + return 1; +} + +/* + * log DNS requests in a separate log + */ +int +slirp_log_dns(struct mbuf* m, int dropped) { + char dns_query[256]; // max allowable dns name size + int c = 0; + int i= 0; + int index = 0; + int offset = 40 + 1; // udp/ip headers length + 1; + int trim_bytes = 4; + + if (!dns_log_fd) + return -1; + + /* We assume one DNS name per query: 300 = 255 (max dns name length) + * + 40 (udp/ip hdr) + 1 byte DNS peamble + 4 bytes DNS suffix + */ + if (m->m_len < offset || m->m_len > 300) { + DEBUG_MISC((dfd,"Malformed DNS qeury, length %d \n", (int)m->m_len)); + return -1; + } + for (i = offset; i < m->m_len - trim_bytes && index < sizeof(dns_query); i++, index++) { + c = m->m_data[i]; + if (c < ' ' || c > '~') + c = '.'; + + dns_query[index] = (char)c; + } + dns_query[index] = '\0'; + if (!dropped) { + fprintf(dns_log_fd, "Sent DNS query for, %s\n" , dns_query); + } else { + fprintf(dns_log_fd, "Dropped DNS query for, %s\n" , dns_query); + } + fflush(dns_log_fd); + return 1; +} + +/* + * log DNS requests in a separate log + */ +int +slirp_dump_dns(struct mbuf* m) { + + if (!dns_log_fd) + return 0; + // first we write the length of the record then the record (IP packet) + if (!fwrite(&(m->m_len), sizeof(int), 1, dns_log_fd) || + !fwrite(m->m_data, m->m_len, 1, dns_log_fd)) { + return 0; + } + + fflush(dns_log_fd); + return 1; +} + +/* Log dropped/accepted packet info */ +int slirp_drop_log(const char* format, ...) { + va_list args; + + if (!drop_log_fd) + return 0; + + va_start(args, format); + vfprintf(drop_log_fd, format, args); + va_end(args); + + fflush(drop_log_fd); + + return 1; +} + + +/* Set max DNS requests allowed to be issued from the VM */ +void slirp_set_max_dns_conns(int num_conns) { + max_dns_conns = num_conns; +} + +int slirp_get_max_dns_conns() { + return max_dns_conns; +} + +/* generic guest network redirection functionality for ipv4 */ +struct net_forward_entry { + QTAILQ_ENTRY(net_forward_entry) next; + /* ip addresses are also in host byte order */ + unsigned long dest_ip; /* the destination address they try to contact */ + unsigned long dest_mask; /* the mask to apply to the address for matching */ + /* Range of ports they were trying to contact. In case of a single port, + * dest_lport should be the same as dest_hport */ + int dest_lport; /* Host byte order */ + int dest_hport; /* Host byte order */ + + unsigned long redirect_ip; + int redirect_port; /* Host byte order */ +}; + +static QTAILQ_HEAD(net_forwardq, net_forward_entry) net_forwards; + +static void slirp_net_forward_init(void) +{ + if (!slirp_net_forward_inited) { + QTAILQ_INIT(&net_forwards); + slirp_net_forward_inited = 1; + } +} + +/* all addresses and ports ae in host byte order */ +void slirp_add_net_forward(unsigned long dest_ip, unsigned long dest_mask, + int dest_lport, int dest_hport, + unsigned long redirect_ip, int redirect_port) +{ + slirp_net_forward_init(); + + struct net_forward_entry *entry = malloc(sizeof(*entry)); + if (entry == NULL) { + DEBUG_MISC((dfd, "Unable to create new forwarding entry, malloc failed\n")); + exit(-1); + } + + entry->dest_ip = dest_ip; + entry->dest_mask = dest_mask; + entry->dest_lport = dest_lport; + entry->dest_hport = dest_hport; + entry->redirect_ip = redirect_ip; + entry->redirect_port = redirect_port; + + QTAILQ_INSERT_TAIL(&net_forwards, entry, next); +} + +/* remote_port and redir_port arguments + * are in network byte order (tcp_subr.c) */ +int slirp_should_net_forward(unsigned long remote_ip, int remote_port, + unsigned long *redirect_ip, int *redirect_port) +{ + struct net_forward_entry *entry; + + for (entry = net_forwards.tqh_first; + entry != NULL; entry = entry->next.tqe_next) { + + if ((entry->dest_lport <= remote_port) + && (remote_port <= entry->dest_hport)) { + if ((entry->dest_ip & entry->dest_mask) + == (remote_ip & entry->dest_mask)) { + *redirect_ip = entry->redirect_ip; + *redirect_port = entry->redirect_port; + return 1; + } + } + } + + return 0; +} + +/*---------------------------------------------------*/ + + + + static void _slirp_redir_loop(void (*func)(void *opaque, int is_udp, const SockAddress *laddr, const SockAddress *faddr), diff --git a/slirp-android/socket.c b/slirp-android/socket.c index 44640a8..285a8ef 100644 --- a/slirp-android/socket.c +++ b/slirp-android/socket.c @@ -570,6 +570,26 @@ sosendto(struct socket *so, struct mbuf *m) addr_port = so->so_faddr_port; + /* + * test for generic forwarding; this function replaces the arguments + * only on success + */ + unsigned long faddr = addr_ip; + int fport = addr_port; + + if (slirp_should_net_forward(faddr, fport, &faddr, &fport)) { + slirp_drop_log( + "Redirected UDP: src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x " + "new dst: 0x%08lx:0x%04x\n", + so->so_laddr_ip, so->so_laddr_port, + addr_ip, addr_port, + faddr, fport + ); + } + addr_ip = faddr; + addr_port = fport; + + sock_address_init_inet(&addr, addr_ip, addr_port); DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%08x\n", addr_port, addr_ip)); @@ -779,4 +799,3 @@ sofwdrain(struct socket *so) else sofcantsendmore(so); } - diff --git a/slirp-android/tcp_subr.c b/slirp-android/tcp_subr.c index b8b680c..0550d4b 100644 --- a/slirp-android/tcp_subr.c +++ b/slirp-android/tcp_subr.c @@ -377,6 +377,29 @@ tcp_proxy_event( struct socket* so, tcp_input(NULL, sizeof(struct ip), so); } + +/* Tests if an IP address corresponds to a special Qemu service (eg, the DNS + * server or the gateway - see ctl.h) and if so, rewrites it with the real + * address of the service. + */ +int is_qemu_special_address(unsigned long dst_addr, unsigned long *redir_addr) +{ + if ((dst_addr & htonl(0xffffff00)) == special_addr_ip) { + /* It's an alias */ + + int last_byte = dst_addr & 0xff; + + if (CTL_IS_DNS(last_byte)) + *redir_addr = dns_addr[last_byte - CTL_DNS]; + else + *redir_addr = loopback_addr_ip; + + return 1; + } + return 0; +} + + /* * Connect to a host on the Internet * Called by tcp_input @@ -390,41 +413,56 @@ tcp_proxy_event( struct socket* so, int tcp_fconnect(struct socket *so) { int ret=0; - int try_proxy = 1; SockAddress sockaddr; - uint32_t sock_ip; - uint16_t sock_port; + unsigned long sock_ip; + int sock_port; DEBUG_CALL("tcp_fconnect"); DEBUG_ARG("so = %lx", (long )so); - sock_ip = so->so_faddr_ip; - sock_port = so->so_faddr_port; - - if ((sock_ip & 0xffffff00) == special_addr_ip) { - /* It's an alias */ - int last_byte = sock_ip & 0xff; - - if (CTL_IS_DNS(last_byte)) - sock_ip = dns_addr[last_byte - CTL_DNS]; - else - sock_ip = loopback_addr_ip; - try_proxy = 0; - } - - sock_address_init_inet( &sockaddr, sock_ip, sock_port ); - - DEBUG_MISC((dfd, " connect()ing, addr=%s, proxy=%d\n", - sock_address_to_string(&sockaddr), try_proxy)); - - if (try_proxy) { - if (!proxy_manager_add(&sockaddr, SOCKET_STREAM, (ProxyEventFunc) tcp_proxy_event, so)) { - soisfconnecting(so); - so->s = -1; - so->so_state |= SS_PROXIFIED; - return 0; - } + /* when true, a connection that otherwise would be dropped will instead be + * redirected to the sink ('-net-forward-tcp2sink') */ + int forward_dropped_to_sink = 0; + + + /*-------------------------------------------------------------*/ + /* User mode network stack restrictions */ + if (slirp_should_drop(so->so_faddr_ip, so->so_faddr_port, IPPROTO_TCP)) { + + /* If forwarding to sink is enabled, don't actually drop it */ + if (slirp_should_forward_dropped_tcp2sink()) { + slirp_drop_log( + "About to be dropped TCP forwarded to sink: " + "src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n", + so->so_laddr_ip, + so->so_laddr_port, + so->so_faddr_ip, + so->so_faddr_port + ); + forward_dropped_to_sink = 1; + } + else { + slirp_drop_log( + "Dropped TCP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n", + so->so_laddr_ip, + so->so_laddr_port, + so->so_faddr_ip, + so->so_faddr_port + ); + //errno = ENETUNREACH; + errno = ECONNREFUSED; + return -1; + } + } else { + slirp_drop_log( + "Allowed TCP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n", + so->so_laddr_ip, + so->so_laddr_port, + so->so_faddr_ip, + so->so_faddr_port + ); } + /*-------------------------------------------------------------*/ if ((ret=so->s=socket_create_inet(SOCKET_STREAM)) >= 0) { @@ -434,6 +472,79 @@ int tcp_fconnect(struct socket *so) socket_set_xreuseaddr(s); socket_set_oobinline(s); + + if (forward_dropped_to_sink) { + + /* This connection would normally be dropped, but since forwarding of + * dropped connections is enabled, redirect it to the sink */ + sock_ip = slirp_get_tcp_sink_ip(); + sock_port= slirp_get_tcp_sink_port(); + slirp_drop_log( + "Redirected would-be dropped TCP to sink: " + "src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x " + "new dst: 0x%08lx:0x%04x\n", + so->so_laddr_ip, so->so_laddr_port, + so->so_faddr_ip, so->so_faddr_port, + sock_ip, sock_port + ); + } + else { /* An allowed connection */ + + unsigned long faddr; + int fport; + + /* Determine if the connection should be redirected + * due to a -net-forward rule */ + /* faddr and fport are modified only on success */ + if (slirp_should_net_forward(so->so_faddr_ip, so->so_faddr_port, + &faddr, &fport)) { + slirp_drop_log( + "Redirected TCP: src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x " + "new dst: 0x%08lx:0x%04x\n", + so->so_laddr_ip, so->so_laddr_port, + so->so_faddr_ip, so->so_faddr_port, + faddr, fport + ); + sock_ip = faddr; /* forced dst addr */ + sock_port= fport; /* forced dst port */ + } + /* Determine if this is a connection to a special qemu service, + * and change the destination address accordingly. + * 'faddr' is modified only onsuccess */ + else if (is_qemu_special_address(so->so_faddr_ip, &faddr)) { + + /* We keep the original destination port. If a special service + * listens on a different port than the standard, then appropriate + * forwarding should be set up using -net-forward, e.g., as it is + * the case with Mawler's DNS traffic, which is redirected to the + * special DNS port: + * -net-forward 0.0.0.0:0.0.0.0:53:127.0.0.1:21737 */ + + sock_ip = faddr; /* real DNS/gateway addr */ + sock_port= so->so_faddr_port;/* original dst port */ + + } + /* A normal connection - keep the original destination addr/port */ + else { + + if (!proxy_manager_add(&sockaddr, SOCKET_STREAM, + (ProxyEventFunc) tcp_proxy_event, so)) { + soisfconnecting(so); + so->s = -1; + so->so_state |= SS_PROXIFIED; + return 0; + } + + sock_ip = so->so_faddr_ip; /* original dst addr */ + sock_port= so->so_faddr_port; /* original dst port */ + } + } + + DEBUG_MISC((dfd, " connect()ing, addr=%s, proxy=%d\n", + sock_address_to_string(&sockaddr), try_proxy)); + + sock_address_init_inet( &sockaddr, sock_ip, sock_port ); + /* We don't care what port we get */ socket_connect(s, &sockaddr); diff --git a/slirp-android/udp.c b/slirp-android/udp.c index 9091505..a9c9a82 100644 --- a/slirp-android/udp.c +++ b/slirp-android/udp.c @@ -47,6 +47,10 @@ struct udpstat udpstat; #endif +/* Keeps track of the number of DNS requests. Used to implement the firewall + * option that restricts the number of DNS requests (-max_dns_conns). */ +u_int dns_num_conns; + struct socket udb; static u_int8_t udp_tos(struct socket *so); @@ -68,6 +72,7 @@ void udp_init(void) { udb.so_next = udb.so_prev = &udb; + dns_num_conns = 0; } /* m->m_data points at ip packet header * m->m_len length ip packet @@ -121,6 +126,33 @@ udp_input(register struct mbuf *m, int iphlen) ip->ip_len = len; } + /* ------------------------------------------------------*/ + /* User mode network stack restrictions */ + /* slirp_should_drop requires host byte ordering in arguments */ + if (slirp_should_drop(ntohl(ip->ip_dst.addr), ntohs(uh->uh_dport.port), + IPPROTO_UDP)) { + slirp_drop_log( + "Dropped UDP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n", + ip->ip_src.addr, + uh->uh_sport.port, + ip->ip_dst.addr, + uh->uh_dport.port + ); + goto bad; /* drop the packet */ + } + else { + slirp_drop_log( + "Allowed UDP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n", + ip->ip_src.addr, + uh->uh_sport.port, + ip->ip_dst.addr, + uh->uh_dport.port + ); + } + /* ------------------------------------------------------*/ + + + /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. @@ -164,6 +196,18 @@ udp_input(register struct mbuf *m, int iphlen) goto bad; } + // DNS logging and FW rules + if (ntohs(uh->uh_dport.port) == 53) { + if (!slirp_dump_dns(m)) { + DEBUG_MISC((dfd,"Error logging DNS packet")); + } + dns_num_conns++; + if (slirp_get_max_dns_conns() != -1 && + dns_num_conns > slirp_get_max_dns_conns()) + goto bad; + } + + /* * Locate pcb for datagram. */ @@ -309,6 +353,13 @@ int udp_output2_(struct socket *so, struct mbuf *m, STAT(udpstat.udps_opackets++); + // DNS logging + if (so != NULL && so->so_faddr_port == htons(53)) { + if (!slirp_dump_dns(m)) { + DEBUG_MISC((dfd,"Error logging DNS packet")); + } + } + error = ip_output(so, m); return (error); diff --git a/slirp-android/udp.h b/slirp-android/udp.h index 4350ec3..2224181 100644 --- a/slirp-android/udp.h +++ b/slirp-android/udp.h @@ -69,7 +69,6 @@ struct udpiphdr { #define ui_ulen ui_u.uh_ulen #define ui_sum ui_u.uh_sum -#ifdef LOG_ENABLED struct udpstat { /* input statistics: */ u_long udps_ipackets; /* total input packets */ @@ -83,7 +82,6 @@ struct udpstat { /* output statistics: */ u_long udps_opackets; /* total output packets */ }; -#endif /* * Names for UDP sysctl objects @@ -91,9 +89,7 @@ struct udpstat { #define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ #define UDPCTL_MAXID 2 -#ifdef LOG_ENABLED extern struct udpstat udpstat; -#endif extern struct socket udb; struct mbuf; diff --git a/vl-android.c b/vl-android.c index caef03d..1afc8d2 100644 --- a/vl-android.c +++ b/vl-android.c @@ -338,9 +338,6 @@ extern char* op_http_proxy; // Path to the file containing specific key character map. char* op_charmap_file = NULL; -/* Framebuffer dimensions, passed with -android-gui option. */ -char* android_op_gui = NULL; - /* Path to hardware initialization file passed with -android-hw option. */ char* android_op_hwini = NULL; @@ -509,42 +506,6 @@ static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data) #endif } -/* Parses -android-gui command line option, extracting width, height and bits - * per pixel parameters for the GUI console used in this session of the - * emulator. -android-gui option contains exactly three comma-separated positive - * integer numbers in strict order: width goes first, width goes next, and bits - * per pixel goes third. This routine verifies that format and return 0 if all - * three numbers were extracted, or -1 if string format was incorrect for that - * option. Note that this routine does not verify that extracted values are - * correct! - */ -static int -parse_androig_gui_option(const char* op, int* width, int* height, int* bpp) -{ - char val[128]; - - if (get_param_value(val, 128, "width", op)) { - *width = strtol(val, NULL, 0); - } else { - fprintf(stderr, "option -android-gui is missing width parameter\n"); - return -1; - } - if (get_param_value(val, 128, "height", op)) { - *height = strtol(val, NULL, 0); - } else { - fprintf(stderr, "option -android-gui is missing height parameter\n"); - return -1; - } - if (get_param_value(val, 128, "bpp", op)) { - *bpp = strtol(val, NULL, 0); - } else { - fprintf(stderr, "option -android-gui is missing bpp parameter\n"); - return -1; - } - - return 0; -} - /***********************************************************/ void hw_error(const char *fmt, ...) { @@ -3659,6 +3620,164 @@ append_param(char* param_str, const char* arg, int size) } } +/* Parses an integer + * Pararm: + * str String containing a number to be parsed. + * result Passes the parsed integer in this argument + * returns 0 if ok, -1 if failed + */ +int +parse_int(const char *str, int *result) +{ + char* r; + *result = strtol(str, &r, 0); + if (r == NULL || *r != '\0') + return -1; + + return 0; +} + + +/* parses a null-terminated string specifying a network port (e.g., "80") or + * port range (e.g., "[6666-7000]"). In case of a single port, lport and hport + * are the same. Returns 0 on success, -1 on error. */ + +int parse_port_range(const char *str, unsigned short *lport, + unsigned short *hport) { + + unsigned int low = 0, high = 0; + char *p, *arg = strdup(str); + + if ((*arg == '[') && ((p = strrchr(arg, ']')) != NULL)) { + p = arg + 1; /* skip '[' */ + low = atoi(strtok(p, "-")); + high = atoi(strtok(NULL, "-")); + if ((low > 0) && (high > 0) && (low < high) && (high < 65535)) { + *lport = low; + *hport = high; + } + } + else { + low = atoi(arg); + if ((0 < low) && (low < 65535)) { + *lport = low; + *hport = low; + } + } + free(arg); + if (low != 0) + return 0; + return -1; +} + +/* + * Implements the generic port forwarding option + */ +void +net_slirp_forward(const char *optarg) +{ + /* + * we expect the following format: + * dst_net:dst_mask:dst_port:redirect_ip:redirect_port OR + * dst_net:dst_mask:[dp_range_start-dp_range_end]:redirect_ip:redirect_port + */ + char *argument = strdup(optarg), *p = argument; + char *dst_net, *dst_mask, *dst_port; + char *redirect_ip, *redirect_port; + uint32_t dnet, dmask, rip; + unsigned short dlport, dhport, rport; + + + dst_net = strtok(p, ":"); + dst_mask = strtok(NULL, ":"); + dst_port = strtok(NULL, ":"); + redirect_ip = strtok(NULL, ":"); + redirect_port = strtok(NULL, ":"); + + if (dst_net == NULL || dst_mask == NULL || dst_port == NULL || + redirect_ip == NULL || redirect_port == NULL) { + fprintf(stderr, + "Invalid argument for -net-forward, we expect " + "dst_net:dst_mask:dst_port:redirect_ip:redirect_port or " + "dst_net:dst_mask:[dp_range_start-dp_range_end]" + ":redirect_ip:redirect_port: %s\n", + optarg); + exit(1); + } + + /* inet_strtoip converts dotted address to host byte order */ + if (inet_strtoip(dst_net, &dnet) == -1) { + fprintf(stderr, "Invalid destination IP net: %s\n", dst_net); + exit(1); + } + if (inet_strtoip(dst_mask, &dmask) == -1) { + fprintf(stderr, "Invalid destination IP mask: %s\n", dst_mask); + exit(1); + } + if (inet_strtoip(redirect_ip, &rip) == -1) { + fprintf(stderr, "Invalid redirect IP address: %s\n", redirect_ip); + exit(1); + } + + if (parse_port_range(dst_port, &dlport, &dhport) == -1) { + fprintf(stderr, "Invalid destination port or port range\n"); + exit(1); + } + + rport = atoi(redirect_port); + if (!rport) { + fprintf(stderr, "Invalid redirect port: %s\n", redirect_port); + exit(1); + } + + dnet &= dmask; + + slirp_add_net_forward(dnet, dmask, dlport, dhport, + rip, rport); + + free(argument); +} + + +/* Parses an -allow-tcp or -allow-udp argument and inserts a corresponding + * entry in the allows list */ +void +slirp_allow(const char *optarg, u_int8_t proto) +{ + /* + * we expect the following format: + * dst_ip:dst_port OR dst_ip:[dst_lport-dst_hport] + */ + char *argument = strdup(optarg), *p = argument; + char *dst_ip_str, *dst_port_str; + uint32_t dst_ip; + unsigned short dst_lport, dst_hport; + + dst_ip_str = strtok(p, ":"); + dst_port_str = strtok(NULL, ":"); + + if (dst_ip_str == NULL || dst_port_str == NULL) { + fprintf(stderr, + "Invalid argument %s for -allow. We expect " + "dst_ip:dst_port or dst_ip:[dst_lport-dst_hport]\n", + optarg); + exit(1); + } + + if (inet_strtoip(dst_ip_str, &dst_ip) == -1) { + fprintf(stderr, "Invalid destination IP address: %s\n", dst_ip_str); + exit(1); + } + if (parse_port_range(dst_port_str, &dst_lport, &dst_hport) == -1) { + fprintf(stderr, "Invalid destination port or port range\n"); + exit(1); + } + + slirp_add_allow(dst_ip, dst_lport, dst_hport, proto); + + free(argument); +} + int main(int argc, char **argv, char **envp) { const char *gdbstub_dev = NULL; @@ -3706,9 +3825,7 @@ int main(int argc, char **argv, char **envp) #endif CPUState *env; int show_vnc_port = 0; -#ifdef CONFIG_STANDALONE_CORE IniFile* hw_ini = NULL; -#endif // CONFIG_STANDALONE_CORE /* Container for the kernel initialization parameters collected in this * routine. */ char kernel_cmdline_append[1024]; @@ -4416,6 +4533,89 @@ int main(int argc, char **argv, char **envp) } } break; + + /* -------------------------------------------------------*/ + /* User mode network stack restrictions */ + case QEMU_OPTION_drop_udp: + slirp_drop_udp(); + break; + case QEMU_OPTION_drop_tcp: + slirp_drop_tcp(); + break; + case QEMU_OPTION_allow_tcp: + slirp_allow(optarg, IPPROTO_TCP); + break; + case QEMU_OPTION_allow_udp: + slirp_allow(optarg, IPPROTO_UDP); + break; + case QEMU_OPTION_drop_log: + { + FILE* drop_log_fd; + drop_log_fd = fopen(optarg, "w"); + + if (!drop_log_fd) { + fprintf(stderr, "Cannot open drop log: %s\n", optarg); + exit(1); + } + + slirp_drop_log_fd(drop_log_fd); + } + break; + + case QEMU_OPTION_dns_log: + { + FILE* dns_log_fd; + dns_log_fd = fopen(optarg, "wb"); + + if (dns_log_fd == NULL) { + fprintf(stderr, "Cannot open dns log: %s\n", optarg); + exit(1); + } + + slirp_dns_log_fd(dns_log_fd); + } + break; + + + case QEMU_OPTION_max_dns_conns: + { + int max_dns_conns = 0; + if (parse_int(optarg, &max_dns_conns)) { + fprintf(stderr, + "qemu: syntax: -max-dns-conns max_connections\n"); + exit(1); + } + if (max_dns_conns <= 0 || max_dns_conns == LONG_MAX) { + fprintf(stderr, + "Invalid arg for max dns connections: %s\n", + optarg); + exit(1); + } + slirp_set_max_dns_conns(max_dns_conns); + } + break; + + case QEMU_OPTION_net_forward: + net_slirp_forward(optarg); + break; + case QEMU_OPTION_net_forward_tcp2sink: + { + SockAddress saddr; + + if (parse_host_port(&saddr, optarg)) { + fprintf(stderr, + "Invalid ip/port %s for " + "-forward-dropped-tcp2sink. " + "We expect 'sink_ip:sink_port'\n", + optarg); + exit(1); + } + slirp_forward_dropped_tcp2sink(saddr.u.inet.address, + saddr.u.inet.port); + } + break; + /* -------------------------------------------------------*/ + case QEMU_OPTION_tb_size: tb_size = strtol(optarg, NULL, 0); if (tb_size < 0) @@ -4508,10 +4708,6 @@ int main(int argc, char **argv, char **envp) op_charmap_file = (char*)optarg; break; - case QEMU_OPTION_android_gui: - android_op_gui = (char*)optarg; - break; - case QEMU_OPTION_android_hw: android_op_hwini = (char*)optarg; break; @@ -4608,17 +4804,6 @@ int main(int argc, char **argv, char **envp) } } - /* Parse GUI option early, so when we init framebuffer in goldfish we have - * saved display parameters. */ - if (android_op_gui) { - if (parse_androig_gui_option(android_op_gui, - &android_display_width, - &android_display_height, - &android_display_bpp)) { - PANIC("Unable to parse -android-gui parameter: %s", android_op_gui); - } - } - /* Initialize character map. */ if (android_charmap_setup(op_charmap_file)) { if (op_charmap_file) { @@ -4641,20 +4826,33 @@ int main(int argc, char **argv, char **envp) data_dir = CONFIG_QEMU_SHAREDIR; } -#ifdef CONFIG_STANDALONE_CORE - /* Initialize hardware configuration. */ - if (android_op_hwini) { - hw_ini = iniFile_newFromFile(android_op_hwini); - if (hw_ini == NULL) { + if (!android_op_hwini) { + PANIC("Missing -android-hw <file> option!"); + } + hw_ini = iniFile_newFromFile(android_op_hwini); + if (hw_ini == NULL) { PANIC("Could not find %s file.", android_op_hwini); - } - } else { - hw_ini = iniFile_newFromMemory("", 0); } - androidHwConfig_read(android_hw, hw_ini); iniFile_free(hw_ini); -#endif // CONFIG_STANDALONE_CORE + + { + int width = android_hw->hw_lcd_width; + int height = android_hw->hw_lcd_height; + int depth = android_hw->hw_lcd_depth; + + /* A bit of sanity checking */ + if (width <= 0 || height <= 0 || + (depth != 16 && depth != 32) || + (((width|height) & 3) != 0) ) + { + PANIC("Invalid display configuration (%d,%d,%d)", + width, height, depth); + } + android_display_width = width; + android_display_height = height; + android_display_bpp = depth; + } #ifdef CONFIG_NAND_LIMITS /* Init nand stuff. */ @@ -4689,11 +4887,10 @@ int main(int argc, char **argv, char **envp) } /* Initialize LCD density */ - if (android_op_lcd_density) { - char* end; - long density = strtol(android_op_lcd_density, &end, 0); - if (end == NULL || *end || density < 0) { - PANIC("option -lcd-density must be a positive integer"); + if (android_hw->hw_lcd_density) { + long density = android_hw->hw_lcd_density; + if (density <= 0) { + PANIC("Invalid hw.lcd.density value: %ld", density); } hwLcd_setBootProperty(density); } @@ -4968,8 +5165,12 @@ int main(int argc, char **argv, char **envp) } /* init the memory */ - if (ram_size == 0) - ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; + if (ram_size == 0) { + ram_size = android_hw->hw_ramSize * 1024LL * 1024; + if (ram_size == 0) { + ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; + } + } #ifdef CONFIG_KQEMU /* FIXME: This is a nasty hack because kqemu can't cope with dynamic @@ -5199,16 +5400,11 @@ int main(int argc, char **argv, char **envp) /* just use the first displaystate for the moment */ ds = get_displaystate(); - if (android_op_gui) { - /* Initialize display from the command line parameters. */ - android_display_reset(ds, - android_display_width, - android_display_height, - android_display_bpp); - } else { - /* By default, use 320x480x16 */ - android_display_reset(ds, 320, 480, 16); - } + /* Initialize display from the command line parameters. */ + android_display_reset(ds, + android_display_width, + android_display_height, + android_display_bpp); if (display_type == DT_DEFAULT) { #if defined(CONFIG_SDL) || defined(CONFIG_COCOA) |