diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:22:36 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:22:36 +0000 |
commit | 6c983bd5dc46406187b3edf67a16f1ea460cb65f (patch) | |
tree | 7d6869a7e3639cc92aab6f34159cfaba1c94b1dd | |
parent | f4f861d5b93e066a0c734a39f7c52a5b70a28d49 (diff) | |
parent | b8fb19acda9835e0577cef9046c1d3124141b770 (diff) | |
download | goldfish-android12-mainline-tzdata-release.tar.gz |
Snap for 6439596 from b8fb19acda9835e0577cef9046c1d3124141b770 to qt-aml-tzdata-releaseq_tzdata_aml_297100400q_tzdata_aml_297100300q_tzdata_aml_297100000q_tzdata_aml_296200000q_tzdata_aml_295600118q_tzdata_aml_295600110q_tzdata_aml_295500002q_tzdata_aml_295500001q_tzdata_aml_294400310android-mainline-12.0.0_r54android-mainline-12.0.0_r111android-mainline-10.0.0_r13android-mainline-10.0.0_r12android-mainline-10.0.0_r11q_tzdata_aml_297100000android12-mainline-tzdata-releaseandroid10-mainline-tzdata-releaseandroid10-android13-mainline-tzdata-release
Change-Id: Ic72743535a20f380954a47049e6ad0738e638a34
202 files changed, 4362 insertions, 5965 deletions
@@ -17,9 +17,6 @@ LOCAL_PATH := $(call my-dir) ifeq ($(BUILD_QEMU_IMAGES),true) - QEMU_CUSTOMIZATIONS := true -endif -ifeq ($(QEMU_CUSTOMIZATIONS),true) INSTALLED_EMULATOR_INFO_TXT_TARGET := $(PRODUCT_OUT)/emulator-info.txt emulator_info_txt := $(wildcard ${LOCAL_PATH}/emulator-info.txt) @@ -28,7 +25,6 @@ ifeq ($(QEMU_CUSTOMIZATIONS),true) $(hide) grep -v '#' $< > $@ $(call dist-for-goals, dist_files, $(INSTALLED_EMULATOR_INFO_TXT_TARGET)) - $(call dist-for-goals, sdk, $(INSTALLED_EMULATOR_INFO_TXT_TARGET)) subdir_makefiles=$(call first-makefiles-under,$(LOCAL_PATH)) $(foreach mk,$(subdir_makefiles),$(info including $(mk) ...)$(eval include $(mk))) diff --git a/AndroidProducts.mk b/AndroidProducts.mk index 3310b9c3..77183bba 100644 --- a/AndroidProducts.mk +++ b/AndroidProducts.mk @@ -1,4 +1,3 @@ PRODUCT_MAKEFILES := \ $(LOCAL_DIR)/kernel-tests/goldfish_kernel_tests_x86_64.mk \ - $(LOCAL_DIR)/sdk_phone_x86_vendor.mk \ - $(LOCAL_DIR)/fvp.mk + $(LOCAL_DIR)/sdk_phone_x86_vendor.mk diff --git a/MultiDisplayProvider/Android.bp b/MultiDisplayProvider/Android.bp deleted file mode 100644 index b0bd4387..00000000 --- a/MultiDisplayProvider/Android.bp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -android_app { - name: "MultiDisplayProvider", - - // Build the application. - - privileged: true, - srcs: ["src/**/*.java"], - platform_apis: true, - certificate: "platform", - resource_dirs: ["res"], - jni_libs: ["libemulator_multidisplay_jni"], - system_ext_specific: true, -} diff --git a/input/qwerty2.idc b/MultiDisplayProvider/Android.mk index ca416651..21918a8e 100644 --- a/input/qwerty2.idc +++ b/MultiDisplayProvider/Android.mk @@ -12,17 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -# -# Emulator keyboard configuration file #2. -# -touch.deviceType = touchScreen -touch.orientationAware = 1 - -keyboard.layout = qwerty -keyboard.characterMap = qwerty2 -keyboard.orientationAware = 0 -keyboard.builtIn = 1 - -cursor.mode = navigation -cursor.orientationAware = 1 +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +# Build the application. +LOCAL_MODULE_TAGS := optional +LOCAL_PRIVILEGED_MODULE := true +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_PACKAGE_NAME := MultiDisplayProvider +LOCAL_PRIVATE_PLATFORM_APIS := true +LOCAL_CERTIFICATE := platform +LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res +LOCAL_JNI_SHARED_LIBRARIES := libemulator_multidisplay_jni +include $(BUILD_PACKAGE) +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/MultiDisplayProvider/jni/Android.bp b/MultiDisplayProvider/jni/Android.bp deleted file mode 100644 index 0fa0b2e1..00000000 --- a/MultiDisplayProvider/jni/Android.bp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2017 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -cc_library_shared { - name: "libemulator_multidisplay_jni", - - srcs: ["com_android_emulator_multidisplay.cpp"], - - include_dirs: ["system/core/base/include"], - - shared_libs: [ - "libandroid_runtime", - "libnativehelper", - "libcutils", - "libutils", - "liblog", - "libui", - "libgui", - ], - - cflags: [ - "-Wall", - "-Wextra", - "-Wno-unused-parameter", - ], - - system_ext_specific: true, -} diff --git a/MultiDisplayProvider/jni/Android.mk b/MultiDisplayProvider/jni/Android.mk new file mode 100644 index 00000000..7ab3c03c --- /dev/null +++ b/MultiDisplayProvider/jni/Android.mk @@ -0,0 +1,41 @@ +# Copyright (C) 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + com_android_emulator_multidisplay.cpp + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + system/core/base/include \ + +LOCAL_SHARED_LIBRARIES := \ + libandroid_runtime \ + libnativehelper \ + libcutils \ + libutils \ + liblog \ + libui \ + libgui \ + +LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter + +LOCAL_MODULE := libemulator_multidisplay_jni +LOCAL_MODULE_TAGS := optional +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_SHARED_LIBRARY) diff --git a/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayService.java b/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayService.java index 923b94bf..608b590a 100644 --- a/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayService.java +++ b/MultiDisplayProvider/src/com/android/emulator/multidisplay/MultiDisplayService.java @@ -45,7 +45,6 @@ public class MultiDisplayService extends Service { private static final int DEL = 2; private static final int mFlags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | - DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT | 1 << 6 |//DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH 1 << 9; //DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; private DisplayManager mDisplayManager; diff --git a/arm32-vendor.mk b/arm32-vendor.mk index f447325e..9a34d5dd 100644 --- a/arm32-vendor.mk +++ b/arm32-vendor.mk @@ -1,3 +1,4 @@ +PRODUCT_KERNEL_VERSION := 4.4 PRODUCT_PROPERTY_OVERRIDES += \ vendor.rild.libpath=/vendor/lib/libgoldfish-ril.so @@ -5,18 +6,14 @@ PRODUCT_PROPERTY_OVERRIDES += \ # Note: the following lines need to stay at the beginning so that it can # take priority and override the rules it inherit from other mk files # see copy file rules in core/Makefile -ifeq ($(QEMU_USE_SYSTEM_EXT_PARTITIONS),true) - PRODUCT_COPY_FILES += \ - device/generic/goldfish/fstab.ranchu.initrd.arm.ex:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ - device/generic/goldfish/fstab.ranchu.arm.ex:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu -else - PRODUCT_COPY_FILES += \ - device/generic/goldfish/fstab.ranchu.initrd.arm:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ - device/generic/goldfish/fstab.ranchu.arm:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu -endif - +PRODUCT_SDK_ADDON_COPY_FILES += \ + device/generic/goldfish/data/etc/advancedFeatures.ini.arm:images/armeabi-v7a/advancedFeatures.ini \ + prebuilts/qemu-kernel/arm64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:images/armeabi-v7a/kernel-ranchu-64 PRODUCT_COPY_FILES += \ - prebuilts/qemu-kernel/arm64/4.4/kernel-qemu2:kernel-ranchu-64 \ + device/generic/goldfish/fstab.ranchu.initrd.arm:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ + device/generic/goldfish/manifest-arm.xml:$(TARGET_COPY_OUT_VENDOR)/manifest.xml \ device/generic/goldfish/data/etc/advancedFeatures.ini.arm:advancedFeatures.ini \ + prebuilts/qemu-kernel/arm64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:kernel-ranchu-64 \ + device/generic/goldfish/fstab.ranchu.arm:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu EMULATOR_VENDOR_NO_GNSS := true diff --git a/arm64-vendor.mk b/arm64-vendor.mk index 6343136b..a05654d1 100644 --- a/arm64-vendor.mk +++ b/arm64-vendor.mk @@ -1,3 +1,4 @@ +PRODUCT_KERNEL_VERSION := 4.4 PRODUCT_PROPERTY_OVERRIDES += \ vendor.rild.libpath=/vendor/lib64/libgoldfish-ril.so @@ -5,20 +6,15 @@ PRODUCT_PROPERTY_OVERRIDES += \ # Note: the following lines need to stay at the beginning so that it can # take priority and override the rules it inherit from other mk files # see copy file rules in core/Makefile -ifeq ($(QEMU_USE_SYSTEM_EXT_PARTITIONS),true) - PRODUCT_COPY_FILES += \ - device/generic/goldfish/fstab.ranchu.initrd.arm.ex:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ - device/generic/goldfish/fstab.ranchu.arm.ex:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu -else - PRODUCT_COPY_FILES += \ - device/generic/goldfish/fstab.ranchu.initrd.arm:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ - device/generic/goldfish/fstab.ranchu.arm:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu -endif - +PRODUCT_SDK_ADDON_COPY_FILES += \ + device/generic/goldfish/data/etc/advancedFeatures.ini.arm:images/arm64-v8a/advancedFeatures.ini \ + prebuilts/qemu-kernel/arm64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:images/arm64-v8a/kernel-ranchu PRODUCT_COPY_FILES += \ - prebuilts/qemu-kernel/arm64/4.4/kernel-qemu2:kernel-ranchu \ + device/generic/goldfish/fstab.ranchu.initrd.arm:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ + device/generic/goldfish/manifest-arm.xml:$(TARGET_COPY_OUT_VENDOR)/manifest.xml \ + device/generic/goldfish/data/etc/advancedFeatures.ini.arm:advancedFeatures.ini \ + prebuilts/qemu-kernel/arm64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:kernel-ranchu \ device/generic/goldfish/fstab.ranchu.arm:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu - EMULATOR_VENDOR_NO_GNSS := true diff --git a/camera/Android.mk b/camera/Android.mk index e5a1b046..088af564 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -122,27 +122,8 @@ LOCAL_SRC_FILES := ${emulator_camera_src} LOCAL_MODULE := camera.ranchu -# Symlink media profile configurations from /vendor/etc to /data/vendor/etc/ -LOCAL_POST_INSTALL_CMD := ln -sf /data/vendor/etc/media_codecs_google_video.xml $(PRODUCT_OUT)/vendor/etc/media_codecs_google_video.xml include $(BUILD_SHARED_LIBRARY) -# Emulator camera - test binary################################################ - -include ${CLEAR_VARS} - -LOCAL_MODULE_RELATIVE_PATH := ${emulator_camera_module_relative_path} -LOCAL_CFLAGS := ${emulator_camera_cflags} -LOCAL_CLANG_CFLAGS += ${emulator_camera_clang_flags} - -LOCAL_SHARED_LIBRARIES := ${emulator_camera_shared_libraries} -LOCAL_STATIC_LIBRARIES := ${emulator_camera_static_libraries} -LOCAL_C_INCLUDES += ${emulator_camera_c_includes} -LOCAL_SRC_FILES := ${emulator_camera_src} -LOCAL_SRC_FILES += EmulatorCameraTest.cpp - -LOCAL_MODULE := emulatorcameratest -include $(BUILD_EXECUTABLE) - # Build all subdirectories ##################################################### include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/camera/EmulatedFakeCamera3.cpp b/camera/EmulatedFakeCamera3.cpp index 16d4d13b..625a0f18 100644 --- a/camera/EmulatedFakeCamera3.cpp +++ b/camera/EmulatedFakeCamera3.cpp @@ -66,13 +66,13 @@ const int32_t EmulatedFakeCamera3::kAvailableFormats[] = { HAL_PIXEL_FORMAT_Y16 }; -const uint32_t EmulatedFakeCamera3::kAvailableRawSizes[6] = { +const uint32_t EmulatedFakeCamera3::kAvailableRawSizes[4] = { 640, 480, - 1280, 720, - 1920, 1080 + 1280, 720 // mSensorWidth, mSensorHeight }; + /** * 3A constants */ @@ -706,7 +706,7 @@ const camera_metadata_t* EmulatedFakeCamera3::constructDefaultRequestSettings( uint8_t afMode = 0; - { + if (mFacingBack) { switch (type) { case CAMERA3_TEMPLATE_PREVIEW: afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE; @@ -730,8 +730,9 @@ const camera_metadata_t* EmulatedFakeCamera3::constructDefaultRequestSettings( afMode = ANDROID_CONTROL_AF_MODE_AUTO; break; } + } else { + afMode = ANDROID_CONTROL_AF_MODE_OFF; } - settings.update(ANDROID_CONTROL_AF_MODE, &afMode, 1); settings.update(ANDROID_CONTROL_AF_REGIONS, controlRegions, 5); @@ -1250,12 +1251,12 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { if (hasCapability(BACKWARD_COMPATIBLE)) { // 5 cm min focus distance for back camera, infinity (fixed focus) for front - const float minFocusDistance = 1.0/0.05; + const float minFocusDistance = mFacingBack ? 1.0/0.05 : 0.0; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, &minFocusDistance, 1); // 5 m hyperfocal distance for back camera, infinity (fixed focus) for front - const float hyperFocalDistance = 1.0/5.0; + const float hyperFocalDistance = mFacingBack ? 1.0/5.0 : 0.0; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE, &hyperFocalDistance, 1); @@ -1286,7 +1287,8 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { // 90 degree rotation to align with long edge of a phone device that's by default portrait static const float qO[] = { 0.707107f, 0.f, 0.f, 0.707107f}; - const float qF[] = {0, 1.f, 0, 0.f}; + // Either a 180-degree rotation for back-facing, or no rotation for front-facing + const float qF[] = {0, (mFacingBack ? 1.f : 0.f), 0, (mFacingBack ? 0.f : 1.f)}; // Quarternion product, orientation change then facing const float lensPoseRotation[] = {qO[0]*qF[0] - qO[1]*qF[1] - qO[2]*qF[2] - qO[3]*qF[3], @@ -1362,18 +1364,22 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { const std::vector<int32_t> availableStreamConfigurationsBasic = { HAL_PIXEL_FORMAT_BLOB, width, height, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 1280, 720, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - HAL_PIXEL_FORMAT_YCbCr_420_888, 1280, 720, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - HAL_PIXEL_FORMAT_BLOB, 1280, 720, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - HAL_PIXEL_FORMAT_YCbCr_420_888, 640, 480, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, - HAL_PIXEL_FORMAT_BLOB, 640, 480, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 320, 240, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_YCbCr_420_888, 320, 240, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_BLOB, 320, 240, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 176, 144, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_YCbCr_420_888, 176, 144, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_BLOB, 176, 144, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 1280, 720, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + HAL_PIXEL_FORMAT_YCbCr_420_888, 1280, 720, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + HAL_PIXEL_FORMAT_BLOB, 1280, 720, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + }; + + // Always need to include 640x480 in basic formats + const std::vector<int32_t> availableStreamConfigurationsBasic640 = { + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + HAL_PIXEL_FORMAT_YCbCr_420_888, 640, 480, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + HAL_PIXEL_FORMAT_BLOB, 640, 480, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT }; const std::vector<int32_t> availableStreamConfigurationsRaw = { @@ -1392,6 +1398,11 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { availableStreamConfigurations.insert(availableStreamConfigurations.end(), availableStreamConfigurationsBasic.begin(), availableStreamConfigurationsBasic.end()); + if (width > 640) { + availableStreamConfigurations.insert(availableStreamConfigurations.end(), + availableStreamConfigurationsBasic640.begin(), + availableStreamConfigurationsBasic640.end()); + } } if (hasCapability(RAW)) { availableStreamConfigurations.insert(availableStreamConfigurations.end(), @@ -1412,18 +1423,22 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { const std::vector<int64_t> availableMinFrameDurationsBasic = { HAL_PIXEL_FORMAT_BLOB, width, height, Sensor::kFrameDurationRange[0], - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 1280, 720, Sensor::kFrameDurationRange[0], - HAL_PIXEL_FORMAT_YCbCr_420_888, 1280, 720, Sensor::kFrameDurationRange[0], - HAL_PIXEL_FORMAT_BLOB, 1280, 720, Sensor::kFrameDurationRange[0], - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, Sensor::kFrameDurationRange[0], - HAL_PIXEL_FORMAT_YCbCr_420_888, 640, 480, Sensor::kFrameDurationRange[0], - HAL_PIXEL_FORMAT_BLOB, 640, 480, Sensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 320, 240, Sensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_YCbCr_420_888, 320, 240, Sensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_BLOB, 320, 240, Sensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 176, 144, Sensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_YCbCr_420_888, 176, 144, Sensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_BLOB, 176, 144, Sensor::kFrameDurationRange[0], + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 1280, 720, Sensor::kFrameDurationRange[0], + HAL_PIXEL_FORMAT_YCbCr_420_888, 1280, 720, Sensor::kFrameDurationRange[0], + HAL_PIXEL_FORMAT_BLOB, 1280, 720, Sensor::kFrameDurationRange[0], + }; + + // Always need to include 640x480 in basic formats + const std::vector<int64_t> availableMinFrameDurationsBasic640 = { + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, Sensor::kFrameDurationRange[0], + HAL_PIXEL_FORMAT_YCbCr_420_888, 640, 480, Sensor::kFrameDurationRange[0], + HAL_PIXEL_FORMAT_BLOB, 640, 480, Sensor::kFrameDurationRange[0] }; const std::vector<int64_t> availableMinFrameDurationsRaw = { @@ -1442,6 +1457,11 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { availableMinFrameDurations.insert(availableMinFrameDurations.end(), availableMinFrameDurationsBasic.begin(), availableMinFrameDurationsBasic.end()); + if (width > 640) { + availableMinFrameDurations.insert(availableMinFrameDurations.end(), + availableMinFrameDurationsBasic640.begin(), + availableMinFrameDurationsBasic640.end()); + } } if (hasCapability(RAW)) { availableMinFrameDurations.insert(availableMinFrameDurations.end(), @@ -1462,27 +1482,31 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { const std::vector<int64_t> availableStallDurationsBasic = { HAL_PIXEL_FORMAT_BLOB, width, height, Sensor::kFrameDurationRange[0], - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 1280, 720, 0, - HAL_PIXEL_FORMAT_YCbCr_420_888, 1280, 720, 0, - HAL_PIXEL_FORMAT_BLOB, 1280, 720, Sensor::kFrameDurationRange[0], - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, 0, - HAL_PIXEL_FORMAT_YCbCr_420_888, 640, 480, 0, - HAL_PIXEL_FORMAT_BLOB, 640, 480, Sensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 320, 240, 0, HAL_PIXEL_FORMAT_YCbCr_420_888, 320, 240, 0, HAL_PIXEL_FORMAT_RGBA_8888, 320, 240, 0, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 176, 144, 0, HAL_PIXEL_FORMAT_YCbCr_420_888, 176, 144, 0, HAL_PIXEL_FORMAT_RGBA_8888, 176, 144, 0, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 1280, 720, 0, + HAL_PIXEL_FORMAT_YCbCr_420_888, 1280, 720, 0, + HAL_PIXEL_FORMAT_RGBA_8888, 1280, 720, 0, + }; + + // Always need to include 640x480 in basic formats + const std::vector<int64_t> availableStallDurationsBasic640 = { + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, 0, + HAL_PIXEL_FORMAT_YCbCr_420_888, 640, 480, 0, + HAL_PIXEL_FORMAT_BLOB, 640, 480, Sensor::kFrameDurationRange[0] }; const std::vector<int64_t> availableStallDurationsRaw = { - HAL_PIXEL_FORMAT_RAW16, width, height, Sensor::kFrameDurationRange[0] + HAL_PIXEL_FORMAT_RAW16, 640, 480, Sensor::kFrameDurationRange[0] }; const std::vector<int64_t> availableStallDurationsBurst = { - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, width, height, 0, - HAL_PIXEL_FORMAT_YCbCr_420_888, width, height, 0, - HAL_PIXEL_FORMAT_RGBA_8888, width, height, 0 + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, 0, + HAL_PIXEL_FORMAT_YCbCr_420_888, 640, 480, 0, + HAL_PIXEL_FORMAT_RGBA_8888, 640, 480, 0 }; std::vector<int64_t> availableStallDurations; @@ -1491,6 +1515,11 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { availableStallDurations.insert(availableStallDurations.end(), availableStallDurationsBasic.begin(), availableStallDurationsBasic.end()); + if (width > 640) { + availableStallDurations.insert(availableStallDurations.end(), + availableStallDurationsBasic640.begin(), + availableStallDurationsBasic640.end()); + } } if (hasCapability(RAW)) { availableStallDurations.insert(availableStallDurations.end(), @@ -1674,7 +1703,7 @@ status_t EmulatedFakeCamera3::constructStaticInfo() { ANDROID_CONTROL_AF_MODE_OFF }; - if (hasCapability(BACKWARD_COMPATIBLE)) { + if (mFacingBack && hasCapability(BACKWARD_COMPATIBLE)) { ADD_STATIC_ENTRY(ANDROID_CONTROL_AF_AVAILABLE_MODES, availableAfModesBack, sizeof(availableAfModesBack)); } else { @@ -2125,6 +2154,11 @@ status_t EmulatedFakeCamera3::doFakeAF(CameraMetadata &settings) { case ANDROID_CONTROL_AF_MODE_MACRO: case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO: case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE: + if (!mFacingBack) { + // Always report INACTIVE for front Emulated Camera + mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE; + return OK; + } break; default: ALOGE("%s: Emulator doesn't support AF mode %d", diff --git a/camera/EmulatedQemuCamera.h b/camera/EmulatedQemuCamera.h index 83397ef3..1b826c7f 100755 --- a/camera/EmulatedQemuCamera.h +++ b/camera/EmulatedQemuCamera.h @@ -66,9 +66,6 @@ protected: /* Supported frame dimensions reported by the camera device. */ String8 mFrameDims; - -private: - using EmulatedCamera::Initialize; }; }; /* namespace android */ diff --git a/camera/EmulatedQemuCamera3.h b/camera/EmulatedQemuCamera3.h index 5656f539..c26f0379 100644 --- a/camera/EmulatedQemuCamera3.h +++ b/camera/EmulatedQemuCamera3.h @@ -120,7 +120,6 @@ private: * Handle interrupt events from the sensor. */ void onQemuSensorEvent(uint32_t frameNumber, Event e, nsecs_t timestamp); - using EmulatedCamera3::Initialize; private: /************************************************************************** diff --git a/camera/EmulatedQemuCameraDevice.h b/camera/EmulatedQemuCameraDevice.h index 2b2dfc9e..1cabd6f1 100755 --- a/camera/EmulatedQemuCameraDevice.h +++ b/camera/EmulatedQemuCameraDevice.h @@ -132,7 +132,7 @@ private: * pair. */ using FrameBufferPair = std::pair<uint8_t*, uint32_t*>; FrameBufferPair mFrameBufferPairs[2]; - using EmulatedCameraDevice::Initialize; + }; }; /* namespace android */ diff --git a/camera/EmulatorCameraTest.cpp b/camera/EmulatorCameraTest.cpp deleted file mode 100644 index 684e6d78..00000000 --- a/camera/EmulatorCameraTest.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include <iostream> -#include <string> -#include <vector> - -#include "fake-pipeline2/Base.h" -#include "QemuClient.h" - -#include <linux/videodev2.h> -#include <utils/Timers.h> - -using namespace android; - -// Test the capture speed of qemu camera, e.g., webcam and virtual scene -int main(int argc, char* argv[]) { - uint32_t pixFmt; - if (!strncmp(argv[1], "RGB", 3)) { - pixFmt = V4L2_PIX_FMT_RGB32; - } else if (!strncmp(argv[1], "NV21", 3)) { - pixFmt = V4L2_PIX_FMT_NV21; - } else if (!strncmp(argv[1], "YV12", 3)) { - pixFmt = V4L2_PIX_FMT_YVU420; - } else { - printf("format error, use RGB, NV21 or YV12"); - return -1; - } - uint32_t width = atoi(argv[2]); - uint32_t height = atoi(argv[3]); - std::string deviceName; - if (!strncmp(argv[4], "web", 3)) { - deviceName = "name=/dev/video0"; - } else if (!strncmp(argv[4], "vir", 3)) { - deviceName = "name=virtualscene"; - } else { - printf("device error, use web or virtual"); - return -1; - } - - // Open qemu pipe - CameraQemuClient client; - int ret = client.connectClient(deviceName.c_str()); - if (ret != NO_ERROR) { - printf("Failed to connect device\n"); - return -1; - } - ret = client.queryConnect(); - if (ret == NO_ERROR) { - printf("Connected to device\n"); - } else { - printf("Failed to connect device\n"); - return -1; - } - - // Caputre ASAP - ret = client.queryStart(pixFmt, width, height); - if (ret != NO_ERROR) { - printf("Failed to configure device for query\n"); - return -1; - } - size_t bufferSize; - if (pixFmt == V4L2_PIX_FMT_RGB32) { - bufferSize = width * height * 4; - } else { - bufferSize = width * height * 12 / 8; - } - std::vector<char> buffer(bufferSize, 0); - float whiteBalance[] = {1.0f, 1.0f, 1.0f}; - float exposureCompensation = 1.0f; - std::vector<nsecs_t> report; - size_t repeated = 100; - for (int i = 0 ; i < repeated; i++) { - nsecs_t start = systemTime(); - client.queryFrame(buffer.data(), nullptr, 0, bufferSize, - whiteBalance[0], whiteBalance[1], whiteBalance[2], - exposureCompensation, nullptr); - nsecs_t end = systemTime(); - report.push_back(end - start); - } - - // Report - nsecs_t average, sum = 0; - for (int i = 0; i < repeated; i++) { - sum += report[i]; - } - average = sum / repeated; - printf("Report for reading %d frames\n", repeated); - printf("\ttime total: %lld\n", sum); - printf("\tframe average: %lld\n", average); - - return 0; -} - diff --git a/camera/Thumbnail.cpp b/camera/Thumbnail.cpp index d3472a4b..8f901a31 100644 --- a/camera/Thumbnail.cpp +++ b/camera/Thumbnail.cpp @@ -27,14 +27,40 @@ #include <vector> /* - * The YU12 format is a YUV format with an 8-bit Y-component and the U and V + * The NV21 format is a YUV format with an 8-bit Y-component and the U and V * components are stored as 8 bits each but they are shared between a block of * 2x2 pixels. So when calculating bits per pixel the 16 bits of U and V are * shared between 4 pixels leading to 4 bits of U and V per pixel. Together * with the 8 bits of Y this gives us 12 bits per pixel.. * - * The components are not grouped by pixels but separated into one Y-plane, one - * U-plane and one V-plane. + * The components are not grouped by pixels but separated into one Y-plane and + * one interleaved U and V-plane. The first half of the byte sequence is all of + * the Y data laid out in a linear fashion. After that the interleaved U and V- + * plane starts with one byte of V followed by one byte of U followed by one + * byte of V and so on. Each byte of U or V is associated with a 2x2 pixel block + * in a linear fashion. + * + * For an 8 by 4 pixel image the layout would be: + * + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | Y0 | Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | Y8 | Y9 | Y10 | Y11 | Y12 | Y13 | Y14 | Y15 | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | Y16 | Y17 | Y18 | Y19 | Y20 | Y21 | Y22 | Y23 | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | Y24 | Y25 | Y26 | Y27 | Y28 | Y29 | Y30 | Y31 | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | V0 | U0 | V1 | U1 | V2 | U2 | V3 | U3 | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | V4 | U4 | V5 | U5 | V6 | U6 | V7 | U7 | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * + * In this image V0 and U0 are the V and U components for the 2x2 block of + * pixels whose Y components are Y0, Y1, Y8 and Y9. V1 and U1 are matched with + * the Y components Y2, Y3, Y10, Y11, and so on for that row. For the next row + * of V and U the V4 and U4 components would be paired with Y16, Y17, Y24 and + * Y25. */ namespace android { @@ -43,9 +69,20 @@ static bool createRawThumbnail(const unsigned char* sourceImage, int sourceWidth, int sourceHeight, int thumbnailWidth, int thumbnailHeight, std::vector<unsigned char>* thumbnail) { + // Deinterleave the U and V planes into separate planes, this is because + // libyuv requires the planes to be separate when scaling + const size_t sourceUVPlaneSize = (sourceWidth * sourceHeight) / 4; + // Put both U and V planes in one buffer, one after the other, to reduce + // memory fragmentation and number of allocations + std::vector<unsigned char> sourcePlanes(sourceUVPlaneSize * 2); const unsigned char* ySourcePlane = sourceImage; - const unsigned char* uSourcePlane = sourceImage + sourceWidth * sourceHeight; - const unsigned char* vSourcePlane = uSourcePlane + sourceWidth * sourceHeight / 4; + unsigned char* uSourcePlane = &sourcePlanes[0]; + unsigned char* vSourcePlane = &sourcePlanes[sourceUVPlaneSize]; + + for (size_t i = 0; i < sourceUVPlaneSize; ++i) { + vSourcePlane[i] = sourceImage[sourceWidth * sourceHeight + i * 2 + 0]; + uSourcePlane[i] = sourceImage[sourceWidth * sourceHeight + i * 2 + 1]; + } // Create enough space in the output vector for the result thumbnail->resize((thumbnailWidth * thumbnailHeight * 12) / 8); @@ -55,8 +92,8 @@ static bool createRawThumbnail(const unsigned char* sourceImage, const size_t destUVPlaneSize = (thumbnailWidth * thumbnailHeight) / 4; std::vector<unsigned char> destPlanes(destUVPlaneSize * 2); unsigned char* yDestPlane = &(*thumbnail)[0]; - unsigned char* uDestPlane = yDestPlane + thumbnailWidth * thumbnailHeight; - unsigned char* vDestPlane = uDestPlane + thumbnailWidth * thumbnailHeight / 4; + unsigned char* uDestPlane = &destPlanes[0]; + unsigned char* vDestPlane = &destPlanes[destUVPlaneSize]; // The strides for the U and V planes are half the width because the U and V // components are common to 2x2 pixel blocks @@ -75,6 +112,14 @@ static bool createRawThumbnail(const unsigned char* sourceImage, return false; } + // Now we need to interleave the downscaled U and V planes into the + // output buffer to make it NV21 encoded + const size_t uvPlanesOffset = thumbnailWidth * thumbnailHeight; + for (size_t i = 0; i < destUVPlaneSize; ++i) { + (*thumbnail)[uvPlanesOffset + i * 2 + 0] = vDestPlane[i]; + (*thumbnail)[uvPlanesOffset + i * 2 + 1] = uDestPlane[i]; + } + return true; } diff --git a/camera/fake-pipeline2/JpegCompressor.h b/camera/fake-pipeline2/JpegCompressor.h index 7a78ef79..493e4a63 100644 --- a/camera/fake-pipeline2/JpegCompressor.h +++ b/camera/fake-pipeline2/JpegCompressor.h @@ -77,7 +77,7 @@ class JpegCompressor: private Thread, public virtual RefBase { status_t reserve(); // TODO: Measure this - static const size_t kMaxJpegSize = 675000; + static const size_t kMaxJpegSize = 300000; private: Mutex mBusyMutex; diff --git a/camera/fake-pipeline2/Scene.cpp b/camera/fake-pipeline2/Scene.cpp index 1bfd216a..0fea38e9 100644 --- a/camera/fake-pipeline2/Scene.cpp +++ b/camera/fake-pipeline2/Scene.cpp @@ -42,8 +42,6 @@ namespace android { const int Scene::kSceneWidth = 20; const int Scene::kSceneHeight = 20; -const int Scene::kMaxWidth = 20; -const int Scene::kMaxHeight = 20; const uint8_t Scene::kScene[Scene::kSceneWidth * Scene::kSceneHeight] = { // 5 10 15 20 @@ -341,15 +339,44 @@ void Scene::calculateScene(nsecs_t time) { setReadoutPixel(0,0); } +void Scene::setReadoutPixel(int x, int y) { + mCurrentX = x; + mCurrentY = y; + mSubX = (x + mOffsetX + mHandshakeX) % mMapDiv; + mSubY = (y + mOffsetY + mHandshakeY) % mMapDiv; + mSceneX = (x + mOffsetX + mHandshakeX) / mMapDiv; + mSceneY = (y + mOffsetY + mHandshakeY) / mMapDiv; + mSceneIdx = mSceneY * kSceneWidth + mSceneX; + mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]); +} + +const uint32_t* Scene::getPixelElectrons() { + const uint32_t *pixel = mCurrentSceneMaterial; + mCurrentX++; + mSubX++; + if (mCurrentX >= mSensorWidth) { + mCurrentX = 0; + mCurrentY++; + if (mCurrentY >= mSensorHeight) mCurrentY = 0; + setReadoutPixel(mCurrentX, mCurrentY); + } else if (mSubX > mMapDiv) { + mSceneIdx++; + mSceneX++; + mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]); + mSubX = 0; + } + return pixel; +} + // Handshake model constants. // Frequencies measured in a nanosecond timebase -const float Scene::kHorizShakeFreq1 = 2 * M_PI * 1 / 1e9; // 1 Hz -const float Scene::kHorizShakeFreq2 = 2 * M_PI * 1 / 1e9; // 1 Hz -const float Scene::kVertShakeFreq1 = 2 * M_PI * 1 / 1e9; // 1 Hz -const float Scene::kVertShakeFreq2 = 2 * M_PI * 1 / 1e9; // 1 Hz +const float Scene::kHorizShakeFreq1 = 2 * M_PI * 2 / 1e9; // 2 Hz +const float Scene::kHorizShakeFreq2 = 2 * M_PI * 13 / 1e9; // 13 Hz +const float Scene::kVertShakeFreq1 = 2 * M_PI * 3 / 1e9; // 3 Hz +const float Scene::kVertShakeFreq2 = 2 * M_PI * 11 / 1e9; // 1 Hz const float Scene::kFreq1Magnitude = 5; const float Scene::kFreq2Magnitude = 1; -const float Scene::kShakeFraction = 0.2; // As a fraction of a scene tile +const float Scene::kShakeFraction = 0.03; // As a fraction of a scene tile // RGB->YUV, Jpeg standard const float Scene::kRgb2Yuv[12] = { diff --git a/camera/fake-pipeline2/Scene.h b/camera/fake-pipeline2/Scene.h index aec53f7c..3a7a001a 100644 --- a/camera/fake-pipeline2/Scene.h +++ b/camera/fake-pipeline2/Scene.h @@ -64,38 +64,13 @@ class Scene { void calculateScene(nsecs_t time); // Set sensor pixel readout location. - inline void setReadoutPixel(int x, int y) { - mCurrentX = x; - mCurrentY = y; - mSubX = (x + mOffsetX + mHandshakeX) % mMapDiv; - mSubY = (y + mOffsetY + mHandshakeY) % mMapDiv; - mSceneX = (x + mOffsetX + mHandshakeX) / mMapDiv; - mSceneY = (y + mOffsetY + mHandshakeY) / mMapDiv; - mSceneIdx = mSceneY * kSceneWidth + mSceneX; - mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]); - } + void setReadoutPixel(int x, int y); // Get sensor response in physical units (electrons) for light hitting the // current readout pixel, after passing through color filters. The readout // pixel will be auto-incremented. The returned array can be indexed with // ColorChannels. - inline const uint32_t* getPixelElectrons() { - const uint32_t *pixel = mCurrentSceneMaterial; - mCurrentX++; - mSubX++; - if (mCurrentX >= mSensorWidth) { - mCurrentX = 0; - mCurrentY++; - if (mCurrentY >= mSensorHeight) mCurrentY = 0; - setReadoutPixel(mCurrentX, mCurrentY); - } else if (mSubX > mMapDiv) { - mSceneIdx++; - mSceneX++; - mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]); - mSubX = 0; - } - return pixel; - } + const uint32_t* getPixelElectrons(); enum ColorChannels { R = 0, @@ -108,11 +83,6 @@ class Scene { NUM_CHANNELS }; - // Max scene width and height. Calculation for larger scene consumes much - // CPU resource. So we put a limit here. - static const int kMaxWidth; - static const int kMaxHeight; - private: // Sensor color filtering coefficients in XYZ float mFilterR[3]; diff --git a/camera/fake-pipeline2/Sensor.cpp b/camera/fake-pipeline2/Sensor.cpp index ab984efe..c5552754 100644 --- a/camera/fake-pipeline2/Sensor.cpp +++ b/camera/fake-pipeline2/Sensor.cpp @@ -17,7 +17,6 @@ //#define LOG_NDEBUG 0 //#define LOG_NNDEBUG 0 #define LOG_TAG "EmulatedCamera2_Sensor" -#define ATRACE_TAG ATRACE_TAG_CAMERA #ifdef LOG_NNDEBUG #define ALOGVV(...) ALOGV(__VA_ARGS__) @@ -26,7 +25,6 @@ #endif #include <log/log.h> -#include <utils/Trace.h> #include "../EmulatedFakeCamera2.h" #include "Sensor.h" @@ -78,7 +76,6 @@ const float Sensor::kReadNoiseVarAfterGain = const int32_t Sensor::kSensitivityRange[2] = {100, 1600}; const uint32_t Sensor::kDefaultSensitivity = 100; - /** A few utility functions for math, normal distributions */ // Take advantage of IEEE floating-point format to calculate an approximate @@ -111,9 +108,7 @@ Sensor::Sensor(uint32_t width, uint32_t height): mFrameNumber(0), mCapturedBuffers(NULL), mListener(NULL), - mSceneWidth((width < Scene::kMaxWidth) ? width : Scene::kMaxWidth), - mSceneHeight((height < Scene::kMaxHeight) ? height : Scene::kMaxHeight), - mScene(mSceneWidth, mSceneHeight, kElectronsPerLuxSecond) + mScene(width, height, kElectronsPerLuxSecond) { ALOGV("Sensor created with pixel array %d x %d", width, height); } @@ -229,7 +224,6 @@ status_t Sensor::readyToRun() { } bool Sensor::threadLoop() { - ATRACE_CALL(); /** * Sensor capture operation main loop. * @@ -353,7 +347,7 @@ bool Sensor::threadLoop() { } break; case HAL_PIXEL_FORMAT_YCbCr_420_888: - captureYU12(b.img, gain, b.width, b.height); + captureNV21(b.img, gain, b.width, b.height); break; case HAL_PIXEL_FORMAT_YV12: // TODO: @@ -390,7 +384,6 @@ bool Sensor::threadLoop() { }; void Sensor::captureRaw(uint8_t *img, uint32_t gain, uint32_t stride) { - ATRACE_CALL(); float totalGain = gain/100.0 * kBaseGainFactor; float noiseVarGain = totalGain * totalGain; float readNoiseVar = kReadNoiseVarBeforeGain * noiseVarGain @@ -432,12 +425,11 @@ void Sensor::captureRaw(uint8_t *img, uint32_t gain, uint32_t stride) { } void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height) { - ATRACE_CALL(); float totalGain = gain/100.0 * kBaseGainFactor; // In fixed-point math, calculate total scaling from electrons to 8bpp int scale64x = 64 * totalGain * 255 / kMaxRawValue; - unsigned int DivH= (float)mSceneHeight/height * (0x1 << 10); - unsigned int DivW = (float)mSceneWidth/width * (0x1 << 10); + unsigned int DivH= (float)mResolution[1]/height * (0x1 << 10); + unsigned int DivW = (float)mResolution[0]/width * (0x1 << 10); for (unsigned int outY = 0; outY < height; outY++) { unsigned int y = outY * DivH >> 10; @@ -455,9 +447,9 @@ void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t width, uint32_t h } lastX = x; // TODO: Perfect demosaicing is a cheat - rCount = pixel[Scene::R] * scale64x; - gCount = pixel[Scene::Gr] * scale64x; - bCount = pixel[Scene::B] * scale64x; + rCount = (pixel[Scene::R]+(outX+outY)%64) * scale64x; + gCount = (pixel[Scene::Gr]+(outX+outY)%64) * scale64x; + bCount = (pixel[Scene::B]+(outX+outY)%64) * scale64x; *px++ = rCount < 255*64 ? rCount / 64 : 255; *px++ = gCount < 255*64 ? gCount / 64 : 255; @@ -471,12 +463,11 @@ void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t width, uint32_t h } void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height) { - ATRACE_CALL(); float totalGain = gain/100.0 * kBaseGainFactor; // In fixed-point math, calculate total scaling from electrons to 8bpp int scale64x = 64 * totalGain * 255 / kMaxRawValue; - unsigned int DivH= (float)mSceneHeight/height * (0x1 << 10); - unsigned int DivW = (float)mSceneWidth/width * (0x1 << 10); + unsigned int DivH= (float)mResolution[1]/height * (0x1 << 10); + unsigned int DivW = (float)mResolution[0]/width * (0x1 << 10); for (unsigned int outY = 0; outY < height; outY++) { unsigned int y = outY * DivH >> 10; @@ -494,9 +485,9 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t width, uint32_t he } lastX = x; // TODO: Perfect demosaicing is a cheat - rCount = pixel[Scene::R] * scale64x; - gCount = pixel[Scene::Gr] * scale64x; - bCount = pixel[Scene::B] * scale64x; + rCount = (pixel[Scene::R]+(outX+outY)%64) * scale64x; + gCount = (pixel[Scene::Gr]+(outX+outY)%64) * scale64x; + bCount = (pixel[Scene::B]+(outX+outY)%64) * scale64x; *px++ = rCount < 255*64 ? rCount / 64 : 255; *px++ = gCount < 255*64 ? gCount / 64 : 255; @@ -506,8 +497,7 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t width, uint32_t he ALOGVV("RGB sensor image captured"); } -void Sensor::captureYU12(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height) { - ATRACE_CALL(); +void Sensor::captureNV21(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height) { float totalGain = gain/100.0 * kBaseGainFactor; // Using fixed-point math with 6 bits of fractional precision. // In fixed-point math, calculate total scaling from electrons to 8bpp @@ -517,27 +507,19 @@ void Sensor::captureYU12(uint8_t *img, uint32_t gain, uint32_t width, uint32_t h // Fixed-point coefficients for RGB-YUV transform // Based on JFIF RGB->YUV transform. // Cb/Cr offset scaled by 64x twice since they're applied post-multiply - float rgbToY[] = {19.0, 37.0, 7.0, 0.0}; - float rgbToCb[] = {-10.0,-21.0, 32.0, 524288.0}; - float rgbToCr[] = {32.0,-26.0, -5.0, 524288.0}; + const int rgbToY[] = {19, 37, 7}; + const int rgbToCb[] = {-10,-21, 32, 524288}; + const int rgbToCr[] = {32,-26, -5, 524288}; // Scale back to 8bpp non-fixed-point const int scaleOut = 64; const int scaleOutSq = scaleOut * scaleOut; // after multiplies - const double invscaleOutSq = 1.0/scaleOutSq; - for (int i=0; i < 4; ++i) { - rgbToY[i] *= invscaleOutSq; - rgbToCb[i] *= invscaleOutSq; - rgbToCr[i] *= invscaleOutSq; - } - unsigned int DivH= (float)mSceneHeight/height * (0x1 << 10); - unsigned int DivW = (float)mSceneWidth/width * (0x1 << 10); + unsigned int DivH= (float)mResolution[1]/height * (0x1 << 10); + unsigned int DivW = (float)mResolution[0]/width * (0x1 << 10); for (unsigned int outY = 0; outY < height; outY++) { unsigned int y = outY * DivH >> 10; uint8_t *pxY = img + outY * width; uint8_t *pxVU = img + (height + outY / 2) * width; - uint8_t *pxU = img + height * width + (outY / 2) * (width / 2); - uint8_t *pxV = pxU + (height / 2) * (width / 2); mScene.setReadoutPixel(0, y); unsigned int lastX = 0; const uint32_t *pixel = mScene.getPixelElectrons(); @@ -550,29 +532,39 @@ void Sensor::captureYU12(uint8_t *img, uint32_t gain, uint32_t width, uint32_t h } } lastX = x; - rCount = pixel[Scene::R] * scale64x; + //Slightly different color for the same Scene, result in larger + //jpeg image size requried by CTS test + //android.provider.cts.MediaStoreUiTest#testImageCapture + rCount = (pixel[Scene::R]+(outX+outY)%64) * scale64x; rCount = rCount < saturationPoint ? rCount : saturationPoint; - gCount = pixel[Scene::Gr] * scale64x; + gCount = (pixel[Scene::Gr]+(outX+outY)%64) * scale64x; gCount = gCount < saturationPoint ? gCount : saturationPoint; - bCount = pixel[Scene::B] * scale64x; + bCount = (pixel[Scene::B]+(outX+outY)%64) * scale64x; bCount = bCount < saturationPoint ? bCount : saturationPoint; - *pxY++ = (rgbToY[0] * rCount + rgbToY[1] * gCount + rgbToY[2] * bCount); + *pxY++ = (rgbToY[0] * rCount + + rgbToY[1] * gCount + + rgbToY[2] * bCount) / scaleOutSq; if (outY % 2 == 0 && outX % 2 == 0) { - *pxV++ = (rgbToCr[0] * rCount + rgbToCr[1] * gCount + rgbToCr[2] * bCount + rgbToCr[3]); - *pxU++ = (rgbToCb[0] * rCount + rgbToCb[1] * gCount + rgbToCb[2] * bCount + rgbToCb[3]); + *pxVU++ = (rgbToCr[0] * rCount + + rgbToCr[1] * gCount + + rgbToCr[2] * bCount + + rgbToCr[3]) / scaleOutSq; + *pxVU++ = (rgbToCb[0] * rCount + + rgbToCb[1] * gCount + + rgbToCb[2] * bCount + + rgbToCb[3]) / scaleOutSq; } } } - ALOGVV("YU21 sensor image captured"); + ALOGVV("NV21 sensor image captured"); } void Sensor::captureDepth(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height) { - ATRACE_CALL(); float totalGain = gain/100.0 * kBaseGainFactor; // In fixed-point math, calculate scaling factor to 13bpp millimeters int scale64x = 64 * totalGain * 8191 / kMaxRawValue; - unsigned int DivH= (float)mSceneHeight/height * (0x1 << 10); - unsigned int DivW = (float)mSceneWidth/width * (0x1 << 10); + unsigned int DivH= (float)mResolution[1]/height * (0x1 << 10); + unsigned int DivW = (float)mResolution[0]/width * (0x1 << 10); for (unsigned int outY = 0; outY < height; outY++) { unsigned int y = outY * DivH >> 10; @@ -599,7 +591,7 @@ void Sensor::captureDepth(uint8_t *img, uint32_t gain, uint32_t width, uint32_t } void Sensor::captureDepthCloud(uint8_t *img) { - ATRACE_CALL(); + android_depth_points *cloud = reinterpret_cast<android_depth_points*>(img); cloud->num_points = 16; diff --git a/camera/fake-pipeline2/Sensor.h b/camera/fake-pipeline2/Sensor.h index 0dc99622..19428612 100644 --- a/camera/fake-pipeline2/Sensor.h +++ b/camera/fake-pipeline2/Sensor.h @@ -231,14 +231,12 @@ class Sensor: private Thread, public virtual RefBase { nsecs_t mNextCaptureTime; Buffers *mNextCapturedBuffers; - int mSceneWidth; - int mSceneHeight; Scene mScene; void captureRaw(uint8_t *img, uint32_t gain, uint32_t stride); void captureRGBA(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height); void captureRGB(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height); - void captureYU12(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height); + void captureNV21(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height); void captureDepth(uint8_t *img, uint32_t gain, uint32_t width, uint32_t height); void captureDepthCloud(uint8_t *img); diff --git a/camera/jpeg-stub/Compressor.cpp b/camera/jpeg-stub/Compressor.cpp index 02a05fd7..3fe0bd6c 100644 --- a/camera/jpeg-stub/Compressor.cpp +++ b/camera/jpeg-stub/Compressor.cpp @@ -33,6 +33,7 @@ bool Compressor::compress(const unsigned char* data, // provide here so just return. return false; } + return compressData(data, exifData); } @@ -79,6 +80,24 @@ bool Compressor::configureCompressor(int width, int height, int quality) { return true; } +static void deinterleave(const uint8_t* vuPlanar, std::vector<uint8_t>& uRows, + std::vector<uint8_t>& vRows, int rowIndex, int width, + int height, int stride) { + int numRows = (height - rowIndex) / 2; + if (numRows > 8) numRows = 8; + for (int row = 0; row < numRows; ++row) { + int offset = ((rowIndex >> 1) + row) * stride; + const uint8_t* vu = vuPlanar + offset; + for (int i = 0; i < (width >> 1); ++i) { + int index = row * (width >> 1) + i; + uRows[index] = vu[1]; + vRows[index] = vu[0]; + vu += 2; + } + } +} + + bool Compressor::compressData(const unsigned char* data, ExifData* exifData) { const uint8_t* y[16]; const uint8_t* cb[8]; @@ -89,8 +108,9 @@ bool Compressor::compressData(const unsigned char* data, ExifData* exifData) { int width = mCompressInfo.image_width; int height = mCompressInfo.image_height; const uint8_t* yPlanar = data; - const uint8_t* uPlanar = yPlanar + width * height; - const uint8_t* vPlanar = uPlanar + width * height / 4; + const uint8_t* vuPlanar = data + (width * height); + std::vector<uint8_t> uRows(8 * (width >> 1)); + std::vector<uint8_t> vRows(8 * (width >> 1)); // NOTE! DANGER! Do not construct any non-trivial objects below setjmp! // The compiler will not generate code to destroy them during the return @@ -108,6 +128,10 @@ bool Compressor::compressData(const unsigned char* data, ExifData* exifData) { // process 16 lines of Y and 8 lines of U/V each time. while (mCompressInfo.next_scanline < mCompressInfo.image_height) { + //deinterleave u and v + deinterleave(vuPlanar, uRows, vRows, mCompressInfo.next_scanline, + width, height, width); + // Jpeg library ignores the rows whose indices are greater than height. for (i = 0; i < 16; i++) { // y row @@ -116,10 +140,11 @@ bool Compressor::compressData(const unsigned char* data, ExifData* exifData) { // construct u row and v row if ((i & 1) == 0) { // height and width are both halved because of downsampling - cb[i/2] = uPlanar + (mCompressInfo.next_scanline + i) * width / 4; - cr[i/2] = vPlanar + (mCompressInfo.next_scanline + i) * width / 4; + offset = (i >> 1) * (width >> 1); + cb[i/2] = &uRows[offset]; + cr[i/2] = &vRows[offset]; } - } + } jpeg_write_raw_data(&mCompressInfo, const_cast<JSAMPIMAGE>(planes), 16); } diff --git a/camera/media_codecs_google_video_default.xml b/camera/media_codecs_google_video.xml index 75f42646..1dbd13df 100644 --- a/camera/media_codecs_google_video_default.xml +++ b/camera/media_codecs_google_video.xml @@ -23,7 +23,6 @@ <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" range="12-11880" /> <Limit name="bitrate" range="1-384000" /> - <Limit name="performance-point-1920x1080" value="30" /> <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.google.h263.decoder" type="video/3gpp"> @@ -32,7 +31,6 @@ <Limit name="size" min="2x2" max="352x288" /> <Limit name="alignment" value="2x2" /> <Limit name="bitrate" range="1-384000" /> - <Limit name="performance-point-1920x1080" value="30" /> <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.google.h264.decoder" type="video/avc"> @@ -42,7 +40,6 @@ <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" range="1-244800" /> <Limit name="bitrate" range="1-12000000" /> - <Limit name="performance-point-1920x1080" value="30" /> <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.google.hevc.decoder" type="video/hevc"> @@ -53,7 +50,6 @@ <Limit name="block-count" range="1-139264" /> <Limit name="blocks-per-second" range="1-2000000" /> <Limit name="bitrate" range="1-10000000" /> - <Limit name="performance-point-1920x1080" value="30" /> <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.google.vp8.decoder" type="video/x-vnd.on2.vp8"> @@ -62,7 +58,6 @@ <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" range="1-1000000" /> <Limit name="bitrate" range="1-40000000" /> - <Limit name="performance-point-1920x1080" value="30" /> <Feature name="adaptive-playback" /> </MediaCodec> <MediaCodec name="OMX.google.vp9.decoder" type="video/x-vnd.on2.vp9"> @@ -71,7 +66,6 @@ <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" range="1-500000" /> <Limit name="bitrate" range="1-40000000" /> - <Limit name="performance-point-1920x1080" value="30" /> <Feature name="adaptive-playback" /> </MediaCodec> </Decoders> diff --git a/camera/media_codecs_google_video_v2.xml b/camera/media_codecs_google_video_v2.xml deleted file mode 100644 index d64d928f..00000000 --- a/camera/media_codecs_google_video_v2.xml +++ /dev/null @@ -1,120 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<Included> - <Decoders> - <MediaCodec name="OMX.google.mpeg4.decoder" type="video/mp4v-es"> - <!-- profiles and levels: ProfileSimple : Level3 --> - <Limit name="size" min="2x2" max="352x288" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="blocks-per-second" range="12-11880" /> - <Limit name="bitrate" range="1-384000" /> - <Limit name="performance-point-1920x1080" value="30" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - <MediaCodec name="OMX.google.h263.decoder" type="video/3gpp"> - <!-- profiles and levels: ProfileBaseline : Level30, ProfileBaseline : Level45 - ProfileISWV2 : Level30, ProfileISWV2 : Level45 --> - <Limit name="size" min="2x2" max="352x288" /> - <Limit name="alignment" value="2x2" /> - <Limit name="bitrate" range="1-384000" /> - <Limit name="performance-point-1920x1080" value="30" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - <MediaCodec name="OMX.google.goldfish.h264.decoder" type="video/avc"> - <!-- profiles and levels: ProfileHigh : Level52 --> - <Limit name="size" min="2x2" max="4080x4080" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent --> - <Limit name="blocks-per-second" range="1-1966080" /> - <Limit name="bitrate" range="1-48000000" /> - <Limit name="performance-point-1920x1080" value="30" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - <MediaCodec name="OMX.google.hevc.decoder" type="video/hevc"> - <!-- profiles and levels: ProfileMain : MainTierLevel51 --> - <Limit name="size" min="2x2" max="4096x4096" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="8x8" /> - <Limit name="block-count" range="1-196608" /> <!-- max 4096x3072 --> - <Limit name="blocks-per-second" range="1-2000000" /> - <Limit name="bitrate" range="1-10000000" /> - <Limit name="performance-point-1920x1080" value="30" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - <MediaCodec name="OMX.google.goldfish.vp8.decoder" type="video/x-vnd.on2.vp8"> - <Limit name="size" min="2x2" max="2048x2048" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="block-count" range="1-16384" /> - <Limit name="blocks-per-second" range="1-1000000" /> - <Limit name="bitrate" range="1-40000000" /> - <Limit name="performance-point-1920x1080" value="30" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - <MediaCodec name="OMX.google.goldfish.vp9.decoder" type="video/x-vnd.on2.vp9"> - <Limit name="size" min="2x2" max="2048x2048" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="block-count" range="1-16384" /> - <Limit name="blocks-per-second" range="1-500000" /> - <Limit name="bitrate" range="1-40000000" /> - <Limit name="performance-point-1920x1080" value="30" /> - <Feature name="adaptive-playback" /> - </MediaCodec> - </Decoders> - - <Encoders> - <MediaCodec name="OMX.google.h263.encoder" type="video/3gpp"> - <!-- profiles and levels: ProfileBaseline : Level45 --> - <Limit name="size" min="176x144" max="176x144" /> - <Limit name="alignment" value="16x16" /> - <Limit name="bitrate" range="1-128000" /> - </MediaCodec> - <MediaCodec name="OMX.google.h264.encoder" type="video/avc"> - <!-- profiles and levels: ProfileBaseline : Level41 --> - <Limit name="size" min="16x16" max="2048x2048" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="block-count" range="1-8192" /> <!-- max 2048x1024 --> - <Limit name="blocks-per-second" range="1-245760" /> - <Limit name="bitrate" range="1-12000000" /> - <Feature name="intra-refresh" /> - </MediaCodec> - <MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es"> - <!-- profiles and levels: ProfileCore : Level2 --> - <Limit name="size" min="16x16" max="176x144" /> - <Limit name="alignment" value="16x16" /> - <Limit name="block-size" value="16x16" /> - <Limit name="blocks-per-second" range="12-1485" /> - <Limit name="bitrate" range="1-64000" /> - </MediaCodec> - <!-- Overwrites the max frame size to 1440p (see b/110911862). --> - <MediaCodec name="OMX.google.vp8.decoder" type="video/x-vnd.on2.vp8" update="true"> - <Limit name="size" min="2x2" max="2560x2560" /> - <Limit name="block-count" range="1-25600" /> - <Limit name="blocks-per-second" range="1-1536000" /> - </MediaCodec> - <!-- Overwrites the max frame size to 1440p (see b/110911862). --> - <MediaCodec name="OMX.google.vp9.decoder" type="video/x-vnd.on2.vp9" update="true"> - <Limit name="size" min="2x2" max="2560x2560" /> - <Limit name="block-count" range="1-25600" /> - <Limit name="blocks-per-second" range="1-768000" /> - </MediaCodec> - </Encoders> -</Included> diff --git a/camera/qemu-pipeline3/QemuSensor.cpp b/camera/qemu-pipeline3/QemuSensor.cpp index db2a66a3..529bf961 100644 --- a/camera/qemu-pipeline3/QemuSensor.cpp +++ b/camera/qemu-pipeline3/QemuSensor.cpp @@ -21,7 +21,6 @@ //#define LOG_NNDEBUG 0 #define LOG_TAG "EmulatedCamera3_QemuSensor" -#define ATRACE_TAG ATRACE_TAG_CAMERA #ifdef LOG_NNDEBUG #define ALOGVV(...) ALOGV(__VA_ARGS__) @@ -36,7 +35,6 @@ #include <cstdlib> #include <linux/videodev2.h> #include <log/log.h> -#include <utils/Trace.h> namespace android { @@ -189,7 +187,6 @@ status_t QemuSensor::readyToRun() { } bool QemuSensor::threadLoop() { - ATRACE_CALL(); /* * Stages are out-of-order relative to a single frame's processing, but * in-order in time. @@ -306,7 +303,7 @@ bool QemuSensor::threadLoop() { } break; case HAL_PIXEL_FORMAT_YCbCr_420_888: - captureYU12(b.img, b.width, b.height, b.stride, ×tamp); + captureNV21(b.img, b.width, b.height, b.stride, ×tamp); break; default: ALOGE("%s: Unknown/unsupported format %x, no output", @@ -346,7 +343,6 @@ bool QemuSensor::threadLoop() { void QemuSensor::captureRGBA(uint8_t *img, uint32_t width, uint32_t height, uint32_t stride, int64_t *timestamp) { - ATRACE_CALL(); status_t res; if (width != (uint32_t)mLastRequestWidth || height != (uint32_t)mLastRequestHeight) { @@ -373,9 +369,9 @@ void QemuSensor::captureRGBA(uint8_t *img, uint32_t width, uint32_t height, /* * Host Camera always assumes V4L2_PIX_FMT_RGB32 as the preview format, * and asks for the video format from the pixFmt parameter, which is - * V4L2_PIX_FMT_YUV420 in our implementation. + * V4L2_PIX_FMT_NV21 in our implementation. */ - uint32_t pixFmt = V4L2_PIX_FMT_YUV420; + uint32_t pixFmt = V4L2_PIX_FMT_NV21; res = mCameraQemuClient.queryStart(pixFmt, width, height); if (res == NO_ERROR) { mLastRequestWidth = width; @@ -415,8 +411,7 @@ void QemuSensor::captureRGB(uint8_t *img, uint32_t width, uint32_t height, uint3 ALOGE("%s: Not implemented", __FUNCTION__); } -void QemuSensor::captureYU12(uint8_t *img, uint32_t width, uint32_t height, uint32_t stride, int64_t *timestamp) { - ATRACE_CALL(); +void QemuSensor::captureNV21(uint8_t *img, uint32_t width, uint32_t height, uint32_t stride, int64_t *timestamp) { status_t res; if (width != (uint32_t)mLastRequestWidth || height != (uint32_t)mLastRequestHeight) { @@ -443,9 +438,9 @@ void QemuSensor::captureYU12(uint8_t *img, uint32_t width, uint32_t height, uint /* * Host Camera always assumes V4L2_PIX_FMT_RGB32 as the preview format, * and asks for the video format from the pixFmt parameter, which is - * V4L2_PIX_FMT_YUV420 in our implementation. + * V4L2_PIX_FMT_NV21 in our implementation. */ - uint32_t pixFmt = V4L2_PIX_FMT_YUV420; + uint32_t pixFmt = V4L2_PIX_FMT_NV21; res = mCameraQemuClient.queryStart(pixFmt, width, height); if (res == NO_ERROR) { mLastRequestWidth = width; @@ -468,7 +463,7 @@ void QemuSensor::captureYU12(uint8_t *img, uint32_t width, uint32_t height, uint width, stride); } - // Calculate the buffer size for YUV420. + // Calculate the buffer size for NV21. size_t bufferSize = (width * height * 12) / 8; // Apply no white balance or exposure compensation. float whiteBalance[] = {1.0f, 1.0f, 1.0f}; @@ -478,7 +473,7 @@ void QemuSensor::captureYU12(uint8_t *img, uint32_t width, uint32_t height, uint whiteBalance[1], whiteBalance[2], exposureCompensation, timestamp); - ALOGVV("YUV420 sensor image captured"); + ALOGVV("NV21 sensor image captured"); } }; // end of namespace android diff --git a/camera/qemu-pipeline3/QemuSensor.h b/camera/qemu-pipeline3/QemuSensor.h index a39d3e56..a867d8ab 100644 --- a/camera/qemu-pipeline3/QemuSensor.h +++ b/camera/qemu-pipeline3/QemuSensor.h @@ -190,7 +190,7 @@ class QemuSensor: private Thread, public virtual RefBase { uint32_t stride, int64_t *timestamp); void captureRGB(uint8_t *img, uint32_t width, uint32_t height, uint32_t stride, int64_t *timestamp); - void captureYU12(uint8_t *img, uint32_t width, uint32_t height, + void captureNV21(uint8_t *img, uint32_t width, uint32_t height, uint32_t stride, int64_t *timestamp); }; diff --git a/data/etc/advancedFeatures.ini b/data/etc/advancedFeatures.ini index 731e3f53..e1f8b6ad 100644 --- a/data/etc/advancedFeatures.ini +++ b/data/etc/advancedFeatures.ini @@ -7,8 +7,4 @@ EncryptUserData = on IntelPerformanceMonitoringUnit = on Wifi = on HostComposition = on -RefCountPipe = on -VirtioInput = on DynamicPartition = on -YUVCache = on -MultiDisplay = on diff --git a/data/etc/config.ini b/data/etc/config.ini index f7025b0f..a28b600d 100644 --- a/data/etc/config.ini +++ b/data/etc/config.ini @@ -1,6 +1,5 @@ avd.ini.encoding=UTF-8 -disk.dataPartition.size=6G -fastboot.forceColdBoot = yes +disk.dataPartition.size=2G hw.accelerometer=yes hw.audioInput=yes hw.battery=yes diff --git a/data/etc/config.ini.nexus5 b/data/etc/config.ini.nexus5 index 6d2da8b8..df58c7ca 100644 --- a/data/etc/config.ini.nexus5 +++ b/data/etc/config.ini.nexus5 @@ -1,6 +1,5 @@ avd.ini.encoding=UTF-8 -disk.dataPartition.size=6G -fastboot.forceColdBoot = yes +disk.dataPartition.size=2G hw.accelerometer=yes hw.audioInput=yes hw.battery=yes diff --git a/data/etc/dummy.vbmeta.img b/data/etc/dummy.vbmeta.img Binary files differdeleted file mode 100644 index 79892eae..00000000 --- a/data/etc/dummy.vbmeta.img +++ /dev/null diff --git a/data/etc/encryptionkey.img b/data/etc/encryptionkey.img Binary files differindex 139b1720..9e0f96a2 100644 --- a/data/etc/encryptionkey.img +++ b/data/etc/encryptionkey.img diff --git a/data/etc/google/user/advancedFeatures.ini b/data/etc/google/user/advancedFeatures.ini new file mode 100644 index 00000000..7ad2fa81 --- /dev/null +++ b/data/etc/google/user/advancedFeatures.ini @@ -0,0 +1,12 @@ +GrallocSync = on +GLDMA = on +LogcatPipe = on +GLAsyncSwap = on +GLESDynamicVersion = on +PlayStoreImage = on +EncryptUserData = on +IntelPerformanceMonitoringUnit = on +Wifi = on +HostComposition = on +DynamicPartition = on +MultiDisplay = on diff --git a/data/etc/user/advancedFeatures.ini b/data/etc/google/userdebug/advancedFeatures.ini index 6c450301..775e5af7 100644 --- a/data/etc/user/advancedFeatures.ini +++ b/data/etc/google/userdebug/advancedFeatures.ini @@ -1,9 +1,8 @@ GrallocSync = on -GLDMA = on LogcatPipe = on GLAsyncSwap = on GLESDynamicVersion = on -PlayStoreImage = on +GLDMA = on EncryptUserData = on IntelPerformanceMonitoringUnit = on Wifi = on @@ -11,3 +10,4 @@ HostComposition = on RefCountPipe = on VirtioInput = on DynamicPartition = on +MultiDisplay = on diff --git a/data/etc/x86/emulatorip b/data/etc/x86/emulatorip Binary files differdeleted file mode 100755 index 72541a37..00000000 --- a/data/etc/x86/emulatorip +++ /dev/null diff --git a/dhcp/client/dhcpclient.cpp b/dhcp/client/dhcpclient.cpp index 0897b4c2..20dd143e 100644 --- a/dhcp/client/dhcpclient.cpp +++ b/dhcp/client/dhcpclient.cpp @@ -50,9 +50,8 @@ static std::string addrToStr(in_addr_t address) { return inet_ntop(AF_INET, &addr, buffer, sizeof(buffer)); } -DhcpClient::DhcpClient(uint32_t options) - : mOptions(options), - mRandomEngine(std::random_device()()), +DhcpClient::DhcpClient() + : mRandomEngine(std::random_device()()), mRandomDistribution(-kTimeoutSpan, kTimeoutSpan), mState(State::Init), mNextTimeout(kInitialTimeout), @@ -420,50 +419,45 @@ bool DhcpClient::configureDhcp(const Message& msg) { } } + res = mInterface.setAddress(mDhcpInfo.offeredAddress); + if (!res) { + ALOGE("Could not configure DHCP: %s", res.c_str()); + return false; + } + + res = mInterface.setSubnetMask(mDhcpInfo.subnetMask); + if (!res) { + ALOGE("Could not configure DHCP: %s", res.c_str()); + return false; + } + + res = mRouter.setDefaultGateway(mDhcpInfo.gateway, mInterface.getIndex()); + if (!res) { + ALOGE("Could not configure DHCP: %s", res.c_str()); + return false; + } char propName[64]; snprintf(propName, sizeof(propName), "net.%s.gw", mInterface.getName().c_str()); - if (property_set(propName, addrToStr(mDhcpInfo.gateway).c_str()) != 0) { - ALOGE("Failed to set %s: %s", propName, strerror(errno)); - } + property_set(propName, addrToStr(mDhcpInfo.gateway).c_str()); int numDnsEntries = sizeof(mDhcpInfo.dns) / sizeof(mDhcpInfo.dns[0]); for (int i = 0; i < numDnsEntries; ++i) { snprintf(propName, sizeof(propName), "net.%s.dns%d", mInterface.getName().c_str(), i + 1); if (mDhcpInfo.dns[i] != 0) { - if (property_set(propName, - addrToStr(mDhcpInfo.dns[i]).c_str()) != 0) { - ALOGE("Failed to set %s: %s", propName, strerror(errno)); - } + property_set(propName, addrToStr(mDhcpInfo.dns[i]).c_str()); } else { // Clear out any previous value here in case it was set - if (property_set(propName, "") != 0) { - ALOGE("Failed to clear %s: %s", propName, strerror(errno)); - } + property_set(propName, ""); } } - res = mInterface.setAddress(mDhcpInfo.offeredAddress, - mDhcpInfo.subnetMask); - if (!res) { - ALOGE("Could not configure DHCP: %s", res.c_str()); - return false; - } - - if ((mOptions & static_cast<uint32_t>(ClientOption::NoGateway)) == 0) { - res = mRouter.setDefaultGateway(mDhcpInfo.gateway, - mInterface.getIndex()); - if (!res) { - ALOGE("Could not configure DHCP: %s", res.c_str()); - return false; - } - } return true; } void DhcpClient::haltNetwork() { - Result res = mInterface.setAddress(0, 0); + Result res = mInterface.setAddress(0); if (!res) { ALOGE("Could not halt network: %s", res.c_str()); } diff --git a/dhcp/client/dhcpclient.h b/dhcp/client/dhcpclient.h index 128d416f..718f4c9c 100644 --- a/dhcp/client/dhcpclient.h +++ b/dhcp/client/dhcpclient.h @@ -27,16 +27,10 @@ #include <random> -// Options to configure the behavior of the DHCP client. -enum class ClientOption : uint32_t { - NoGateway = (1 << 0), // Do not configure the system's default gateway -}; class DhcpClient { public: - // Create a DHCP client with the given |options|. These options are values - // from the ClientOption enum. - explicit DhcpClient(uint32_t options); + DhcpClient(); // Initialize the DHCP client to listen on |interfaceName|. Result init(const char* interfaceName); @@ -78,7 +72,6 @@ private: uint16_t sourcePort, uint16_t destinationPort, const uint8_t* data, size_t size); - uint32_t mOptions; std::mt19937 mRandomEngine; // Mersenne Twister RNG std::uniform_int_distribution<int> mRandomDistribution; diff --git a/dhcp/client/interface.cpp b/dhcp/client/interface.cpp index a13af084..805fa521 100644 --- a/dhcp/client/interface.cpp +++ b/dhcp/client/interface.cpp @@ -16,26 +16,13 @@ #include "interface.h" -#include "netlink.h" - #include <errno.h> #include <linux/if.h> #include <linux/if_ether.h> #include <linux/route.h> -#include <linux/rtnetlink.h> #include <string.h> #include <unistd.h> -in_addr_t broadcastFromNetmask(in_addr_t address, in_addr_t netmask) { - // The broadcast address is the address with the bits excluded in the - // netmask set to 1. For example if address = 10.0.2.15 and netmask is - // 255.255.255.0 then the broadcast is 10.0.2.255. If instead netmask was - // 255.0.0.0.0 then the broadcast would be 10.255.255.255 - // - // Simply set all the lower bits to 1 and that should do it. - return address | (~netmask); -} - Interface::Interface() : mSocketFd(-1) { } @@ -53,7 +40,7 @@ Result Interface::init(const char* interfaceName) { return Result::error("Interface initialized more than once"); } - mSocketFd = ::socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); + mSocketFd = ::socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP); if (mSocketFd == -1) { return Result::error("Failed to create interface socket for '%s': %s", interfaceName, strerror(errno)); @@ -74,7 +61,7 @@ Result Interface::init(const char* interfaceName) { return res; } - res = setAddress(0, 0); + res = setAddress(0); if (!res) { return res; } @@ -106,65 +93,37 @@ Result Interface::setMtu(uint16_t mtu) { return Result::success(); } -Result Interface::setAddress(in_addr_t address, in_addr_t subnetMask) { - struct Request { - struct nlmsghdr hdr; - struct ifaddrmsg msg; - char buf[256]; - } request; +Result Interface::setAddress(in_addr_t address) { + struct ifreq request = createRequest(); - memset(&request, 0, sizeof(request)); + auto requestAddr = reinterpret_cast<struct sockaddr_in*>(&request.ifr_addr); + requestAddr->sin_family = AF_INET; + requestAddr->sin_port = 0; + requestAddr->sin_addr.s_addr = address; - request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg)); - request.hdr.nlmsg_type = RTM_NEWADDR; - request.hdr.nlmsg_flags = NLM_F_REQUEST | - NLM_F_ACK | - NLM_F_CREATE | - NLM_F_REPLACE; - - request.msg.ifa_family = AF_INET; - // Count the number of bits in the subnet mask, this is the length. - request.msg.ifa_prefixlen = __builtin_popcount(subnetMask); - request.msg.ifa_index = mIndex; - - addRouterAttribute(request, IFA_ADDRESS, &address, sizeof(address)); - addRouterAttribute(request, IFA_LOCAL, &address, sizeof(address)); - in_addr_t broadcast = broadcastFromNetmask(address, subnetMask); - addRouterAttribute(request, IFA_BROADCAST, &broadcast, sizeof(broadcast)); - - struct sockaddr_nl nlAddr; - memset(&nlAddr, 0, sizeof(nlAddr)); - nlAddr.nl_family = AF_NETLINK; - - int status = ::sendto(mSocketFd, &request, request.hdr.nlmsg_len, 0, - reinterpret_cast<sockaddr*>(&nlAddr), - sizeof(nlAddr)); - if (status == -1) { - return Result::error("Unable to set interface address: %s", - strerror(errno)); - } - char buffer[8192]; - status = ::recv(mSocketFd, buffer, sizeof(buffer), 0); - if (status < 0) { - return Result::error("Unable to read netlink response: %s", - strerror(errno)); - } - size_t responseSize = static_cast<size_t>(status); - if (responseSize < sizeof(nlmsghdr)) { - return Result::error("Received incomplete response from netlink"); + int status = ::ioctl(mSocketFd, SIOCSIFADDR, &request); + if (status != 0) { + return Result::error("Failed to set interface address for '%s': %s", + mInterfaceName.c_str(), strerror(errno)); } - auto response = reinterpret_cast<const nlmsghdr*>(buffer); - if (response->nlmsg_type == NLMSG_ERROR) { - if (responseSize < NLMSG_HDRLEN + sizeof(nlmsgerr)) { - return Result::error("Recieved an error from netlink but the " - "response was incomplete"); - } - auto err = reinterpret_cast<const nlmsgerr*>(NLMSG_DATA(response)); - if (err->error) { - return Result::error("Could not set interface address: %s", - strerror(-err->error)); - } + + return Result::success(); +} + +Result Interface::setSubnetMask(in_addr_t subnetMask) { + struct ifreq request = createRequest(); + + auto addr = reinterpret_cast<struct sockaddr_in*>(&request.ifr_addr); + addr->sin_family = AF_INET; + addr->sin_port = 0; + addr->sin_addr.s_addr = subnetMask; + + int status = ::ioctl(mSocketFd, SIOCSIFNETMASK, &request); + if (status != 0) { + return Result::error("Failed to set subnet mask for '%s': %s", + mInterfaceName.c_str(), strerror(errno)); } + return Result::success(); } diff --git a/dhcp/client/interface.h b/dhcp/client/interface.h index ca9e9e5a..b7f549af 100644 --- a/dhcp/client/interface.h +++ b/dhcp/client/interface.h @@ -40,7 +40,8 @@ public: Result bringUp(); Result bringDown(); Result setMtu(uint16_t mtu); - Result setAddress(in_addr_t address, in_addr_t subnetMask); + Result setAddress(in_addr_t address); + Result setSubnetMask(in_addr_t subnetMask); private: struct ifreq createRequest() const; diff --git a/dhcp/client/main.cpp b/dhcp/client/main.cpp index 70b854f4..f4a3ea98 100644 --- a/dhcp/client/main.cpp +++ b/dhcp/client/main.cpp @@ -18,9 +18,7 @@ #include "log.h" static void usage(const char* program) { - ALOGE("Usage: %s [--no-gateway] -i <interface>", program); - ALOGE(" If the optional parameter --no-gateway is specified the client"); - ALOGE(" will not configure the default gateway of the system."); + ALOGE("Usage: %s -i <interface>", program); } int main(int argc, char* argv[]) { @@ -29,7 +27,6 @@ int main(int argc, char* argv[]) { return 1; } const char* interfaceName = nullptr; - uint32_t options = 0; for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "-i") == 0) { @@ -40,8 +37,6 @@ int main(int argc, char* argv[]) { usage(argv[0]); return 1; } - } else if (strcmp(argv[i], "--no-gateway") == 0) { - options |= static_cast<uint32_t>(ClientOption::NoGateway); } else { ALOGE("ERROR: unknown parameters %s", argv[i]); usage(argv[0]); @@ -54,7 +49,7 @@ int main(int argc, char* argv[]) { return 1; } - DhcpClient client(options); + DhcpClient client; Result res = client.init(interfaceName); if (!res) { ALOGE("Failed to initialize DHCP client: %s\n", res.c_str()); diff --git a/dhcp/client/netlink.h b/dhcp/client/netlink.h deleted file mode 100644 index e0c916f3..00000000 --- a/dhcp/client/netlink.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include <linux/rtnetlink.h> - -template<class Request> -inline void addRouterAttribute(Request& r, - int type, - const void* data, - size_t size) { - // Calculate the offset into the character buffer where the RTA data lives - // We use offsetof on the buffer to get it. This avoids undefined behavior - // by casting the buffer (which is safe because it's char) instead of the - // Request struct.(which is undefined because of aliasing) - size_t offset = NLMSG_ALIGN(r.hdr.nlmsg_len) - offsetof(Request, buf); - auto attr = reinterpret_cast<struct rtattr*>(r.buf + offset); - attr->rta_type = type; - attr->rta_len = RTA_LENGTH(size); - memcpy(RTA_DATA(attr), data, size); - - // Update the message length to include the router attribute. - r.hdr.nlmsg_len = NLMSG_ALIGN(r.hdr.nlmsg_len) + RTA_ALIGN(attr->rta_len); -} diff --git a/dhcp/client/router.cpp b/dhcp/client/router.cpp index 7c87e2d9..9b9f17d6 100644 --- a/dhcp/client/router.cpp +++ b/dhcp/client/router.cpp @@ -16,14 +16,31 @@ #include "router.h" -#include "netlink.h" - #include <linux/rtnetlink.h> #include <errno.h> #include <string.h> #include <unistd.h> +template<class Request> +static void addRouterAttribute(Request& r, + int type, + const void* data, + size_t size) { + // Calculate the offset into the character buffer where the RTA data lives + // We use offsetof on the buffer to get it. This avoids undefined behavior + // by casting the buffer (which is safe because it's char) instead of the + // Request struct.(which is undefined because of aliasing) + size_t offset = NLMSG_ALIGN(r.hdr.nlmsg_len) - offsetof(Request, buf); + auto attr = reinterpret_cast<struct rtattr*>(r.buf + offset); + attr->rta_type = type; + attr->rta_len = RTA_LENGTH(size); + memcpy(RTA_DATA(attr), data, size); + + // Update the message length to include the router attribute. + r.hdr.nlmsg_len = NLMSG_ALIGN(r.hdr.nlmsg_len) + RTA_ALIGN(attr->rta_len); +} + Router::Router() : mSocketFd(-1) { } diff --git a/dhcp/server/Android.mk b/dhcp/server/Android.mk new file mode 100644 index 00000000..38234de4 --- /dev/null +++ b/dhcp/server/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + dhcpserver.cpp \ + main.cpp \ + ../common/message.cpp \ + ../common/socket.cpp \ + ../common/utils.cpp \ + + +LOCAL_CPPFLAGS += -Werror +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../common +LOCAL_SHARED_LIBRARIES := libcutils liblog +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := dhcpserver + +LOCAL_MODULE_CLASS := EXECUTABLES + +include $(BUILD_EXECUTABLE) + diff --git a/dhcp/server/dhcpserver.cpp b/dhcp/server/dhcpserver.cpp new file mode 100644 index 00000000..d6d4a7ba --- /dev/null +++ b/dhcp/server/dhcpserver.cpp @@ -0,0 +1,390 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dhcpserver.h" + +#include "dhcp.h" +#include "log.h" +#include "message.h" + +#include <arpa/inet.h> +#include <errno.h> +#include <linux/sockios.h> +#include <net/if.h> +#include <netinet/in.h> +#include <poll.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <cutils/properties.h> + +static const int kMaxDnsServers = 4; + +DhcpServer::DhcpServer(unsigned int excludeInterface) : + mExcludeInterface(excludeInterface) +{ +} + +Result DhcpServer::init() { + Result res = mSocket.open(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (!res) { + return res; + } + res = mSocket.enableOption(SOL_IP, IP_PKTINFO); + if (!res) { + return res; + } + res = mSocket.enableOption(SOL_SOCKET, SO_BROADCAST); + if (!res) { + return res; + } + + res = mSocket.bindIp(INADDR_ANY, PORT_BOOTP_SERVER); + if (!res) { + return res; + } + + return Result::success(); +} + +Result DhcpServer::run() { + // Block all signals while we're running. This way we don't have to deal + // with things like EINTR. We then uses ppoll to set the original mask while + // polling. This way polling can be interrupted but socket writing, reading + // and ioctl remain interrupt free. If a signal arrives while we're blocking + // it it will be placed in the signal queue and handled once ppoll sets the + // original mask. This way no signals are lost. + sigset_t blockMask, originalMask; + int status = ::sigfillset(&blockMask); + if (status != 0) { + return Result::error("Unable to fill signal set: %s", strerror(errno)); + } + status = ::sigprocmask(SIG_SETMASK, &blockMask, &originalMask); + if (status != 0) { + return Result::error("Unable to set signal mask: %s", strerror(errno)); + } + + struct pollfd fds; + fds.fd = mSocket.get(); + fds.events = POLLIN; + Message message; + while ((status = ::ppoll(&fds, 1, nullptr, &originalMask)) >= 0) { + if (status == 0) { + // Timeout + continue; + } + + unsigned int interfaceIndex = 0; + Result res = mSocket.receiveFromInterface(&message, + &interfaceIndex); + if (!res) { + ALOGE("Failed to recieve on socket: %s", res.c_str()); + continue; + } + if (interfaceIndex == 0 || mExcludeInterface == interfaceIndex) { + // Received packet on unknown or unwanted interface, drop it + continue; + } + if (!message.isValidDhcpMessage(OP_BOOTREQUEST)) { + // Not a DHCP request, drop it + continue; + } + switch (message.type()) { + case DHCPDISCOVER: + // Someone is trying to find us, let them know we exist + sendDhcpOffer(message, interfaceIndex); + break; + case DHCPREQUEST: + // Someone wants a lease based on an offer + if (isValidDhcpRequest(message, interfaceIndex)) { + // The request matches our offer, acknowledge it + sendAck(message, interfaceIndex); + } else { + // Request for something other than we offered, denied + sendNack(message, interfaceIndex); + } + break; + } + } + // Polling failed, exit + return Result::error("Polling failed: %s", strerror(errno)); +} + +Result DhcpServer::sendMessage(unsigned int interfaceIndex, + in_addr_t /*sourceAddress*/, + const Message& message) { + return mSocket.sendOnInterface(interfaceIndex, + INADDR_BROADCAST, + PORT_BOOTP_CLIENT, + message); +} + +void DhcpServer::sendDhcpOffer(const Message& message, + unsigned int interfaceIndex ) { + updateDnsServers(); + in_addr_t offerAddress; + in_addr_t netmask; + in_addr_t gateway; + Result res = getOfferAddress(interfaceIndex, + message.dhcpData.chaddr, + &offerAddress, + &netmask, + &gateway); + if (!res) { + ALOGE("Failed to get address for offer: %s", res.c_str()); + return; + } + in_addr_t serverAddress; + res = getInterfaceAddress(interfaceIndex, &serverAddress); + if (!res) { + ALOGE("Failed to get address for interface %u: %s", + interfaceIndex, res.c_str()); + return; + } + + Message offer = Message::offer(message, + serverAddress, + offerAddress, + netmask, + gateway, + mDnsServers.data(), + mDnsServers.size()); + res = sendMessage(interfaceIndex, serverAddress, offer); + if (!res) { + ALOGE("Failed to send DHCP offer: %s", res.c_str()); + } +} + +void DhcpServer::sendAck(const Message& message, unsigned int interfaceIndex) { + updateDnsServers(); + in_addr_t offerAddress; + in_addr_t netmask; + in_addr_t gateway; + in_addr_t serverAddress; + Result res = getOfferAddress(interfaceIndex, + message.dhcpData.chaddr, + &offerAddress, + &netmask, + &gateway); + if (!res) { + ALOGE("Failed to get address for offer: %s", res.c_str()); + return; + } + res = getInterfaceAddress(interfaceIndex, &serverAddress); + if (!res) { + ALOGE("Failed to get address for interface %u: %s", + interfaceIndex, res.c_str()); + return; + } + Message ack = Message::ack(message, + serverAddress, + offerAddress, + netmask, + gateway, + mDnsServers.data(), + mDnsServers.size()); + res = sendMessage(interfaceIndex, serverAddress, ack); + if (!res) { + ALOGE("Failed to send DHCP ack: %s", res.c_str()); + } +} + +void DhcpServer::sendNack(const Message& message, unsigned int interfaceIndex) { + in_addr_t serverAddress; + Result res = getInterfaceAddress(interfaceIndex, &serverAddress); + if (!res) { + ALOGE("Failed to get address for interface %u: %s", + interfaceIndex, res.c_str()); + return; + } + Message nack = Message::nack(message, serverAddress); + res = sendMessage(interfaceIndex, serverAddress, nack); + if (!res) { + ALOGE("Failed to send DHCP nack: %s", res.c_str()); + } +} + +bool DhcpServer::isValidDhcpRequest(const Message& message, + unsigned int interfaceIndex) { + in_addr_t offerAddress; + in_addr_t netmask; + in_addr_t gateway; + Result res = getOfferAddress(interfaceIndex, + message.dhcpData.chaddr, + &offerAddress, + &netmask, + &gateway); + if (!res) { + ALOGE("Failed to get address for offer: %s", res.c_str()); + return false; + } + if (message.requestedIp() != offerAddress) { + ALOGE("Client requested a different IP address from the offered one"); + return false; + } + return true; +} + +void DhcpServer::updateDnsServers() { + char key[64]; + char value[PROPERTY_VALUE_MAX]; + mDnsServers.clear(); + for (int i = 1; i <= kMaxDnsServers; ++i) { + snprintf(key, sizeof(key), "net.eth0.dns%d", i); + if (property_get(key, value, nullptr) > 0) { + struct in_addr address; + if (::inet_pton(AF_INET, value, &address) > 0) { + mDnsServers.push_back(address.s_addr); + } + } + } +} + +Result DhcpServer::getInterfaceData(unsigned int interfaceIndex, + unsigned long type, + struct ifreq* response) { + char interfaceName[IF_NAMESIZE + 1]; + if (if_indextoname(interfaceIndex, interfaceName) == nullptr) { + return Result::error("Failed to get interface name for index %u: %s", + interfaceIndex, strerror(errno)); + } + memset(response, 0, sizeof(*response)); + response->ifr_addr.sa_family = AF_INET; + strncpy(response->ifr_name, interfaceName, IFNAMSIZ - 1); + + if (::ioctl(mSocket.get(), type, response) == -1) { + return Result::error("Failed to get data for interface %s: %s", + interfaceName, strerror(errno)); + } + + return Result::success(); +} + +Result DhcpServer::getInterfaceAddress(unsigned int interfaceIndex, + in_addr_t* address) { + struct ifreq data; + Result res = getInterfaceData(interfaceIndex, SIOCGIFADDR, &data); + if (res.isSuccess()) { + auto inAddr = reinterpret_cast<struct sockaddr_in*>(&data.ifr_addr); + *address = inAddr->sin_addr.s_addr; + } + return res; +} + +Result DhcpServer::getInterfaceNetmask(unsigned int interfaceIndex, + in_addr_t* address) { + struct ifreq data; + Result res = getInterfaceData(interfaceIndex, SIOCGIFNETMASK, &data); + if (res.isSuccess()) { + auto inAddr = reinterpret_cast<struct sockaddr_in*>(&data.ifr_addr); + *address = inAddr->sin_addr.s_addr; + } + return res; +} + +static bool isValidHost(const in_addr_t address, + const in_addr_t interfaceAddress, + const in_addr_t netmask) { + // If the bits outside of the netmask are all zero it's a network address, + // don't use this. + bool isNetworkAddress = (address & ~netmask) == 0; + // If all bits outside of the netmask are set then it's a broadcast address, + // don't use this either. + bool isBroadcastAddress = (address & ~netmask) == ~netmask; + // Don't assign the interface address to a host + bool isInterfaceAddress = address == interfaceAddress; + + return !isNetworkAddress && !isBroadcastAddress && !isInterfaceAddress; +} + +static bool addressInRange(const in_addr_t address, + const in_addr_t interfaceAddress, + const in_addr_t netmask) { + if (address <= (interfaceAddress & netmask)) { + return false; + } + if (address >= (interfaceAddress | ~netmask)) { + return false; + } + return true; +} + +Result DhcpServer::getOfferAddress(unsigned int interfaceIndex, + const uint8_t* macAddress, + in_addr_t* address, + in_addr_t* netmask, + in_addr_t* gateway) { + // The interface address will be the gateway and will be used to determine + // the range of valid addresses (along with the netmask) for the client. + in_addr_t interfaceAddress = 0; + Result res = getInterfaceAddress(interfaceIndex, &interfaceAddress); + if (!res) { + return res; + } + // The netmask of the interface will be the netmask for the client as well + // as used to determine network range. + in_addr_t mask = 0; + res = getInterfaceNetmask(interfaceIndex, &mask); + if (!res) { + return res; + } + + // Assign these values now before they are modified below + *gateway = interfaceAddress; + *netmask = mask; + + Lease key(interfaceIndex, macAddress); + + // Find or create entry, if it's created it will be zero and we update it + in_addr_t& value = mLeases[key]; + if (value == 0) { + // Addresses are stored in network byte order so when doing math on them + // they have to be converted to host byte order + interfaceAddress = ntohl(interfaceAddress); + mask = ntohl(mask); + // Get a reference to the offset so we can use it and increase it at the + // same time. If the entry does not exist it will be created with a + // value of zero. + in_addr_t& offset = mNextAddressOffsets[interfaceIndex]; + if (offset == 0) { + // Increase if zero to avoid assigning network address + ++offset; + } + // Start out at the first address in the range as determined by netmask + in_addr_t nextAddress = (interfaceAddress & mask) + offset; + + // Ensure the address is valid + while (!isValidHost(nextAddress, interfaceAddress, mask) && + addressInRange(nextAddress, interfaceAddress, mask)) { + ++nextAddress; + ++offset; + } + + if (addressInRange(nextAddress, interfaceAddress, mask)) { + // Convert back to network byte order + value = htonl(nextAddress); + ++offset; + } else { + // Ran out of addresses + return Result::error("DHCP server is out of addresses"); + } + } + *address = value; + return Result::success(); +} + diff --git a/dhcp/server/dhcpserver.h b/dhcp/server/dhcpserver.h new file mode 100644 index 00000000..276cd5b1 --- /dev/null +++ b/dhcp/server/dhcpserver.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "lease.h" +#include "result.h" +#include "socket.h" + +#include <netinet/in.h> +#include <stdint.h> + +#include <unordered_map> +#include <vector> + +class Message; + +class DhcpServer { +public: + // Construct a DHCP server. Ignore any requests and discoveries coming on + // the network interface identified by |excludeInterface|. + explicit DhcpServer(unsigned int excludeInterface); + + Result init(); + Result run(); + +private: + Result sendMessage(unsigned int interfaceIndex, + in_addr_t sourceAddress, + const Message& message); + + void sendDhcpOffer(const Message& message, unsigned int interfaceIndex); + void sendAck(const Message& message, unsigned int interfaceIndex); + void sendNack(const Message& message, unsigned int interfaceIndex); + + bool isValidDhcpRequest(const Message& message, + unsigned int interfaceIndex); + void updateDnsServers(); + Result getInterfaceData(unsigned int interfaceIndex, + unsigned long type, + struct ifreq* response); + Result getInterfaceAddress(unsigned int interfaceIndex, + in_addr_t* address); + Result getInterfaceNetmask(unsigned int interfaceIndex, + in_addr_t* netmask); + Result getOfferAddress(unsigned int interfaceIndex, + const uint8_t* macAddress, + in_addr_t* address, + in_addr_t* netmask, + in_addr_t* gateway); + + Socket mSocket; + // This is the next address offset. This will be added to whatever the base + // address of the DHCP address range is. For each new MAC address seen this + // value will increase by one. + std::vector<in_addr_t> mDnsServers; + // Map a lease to an IP address for that lease + std::unordered_map<Lease, in_addr_t> mLeases; + std::unordered_map<unsigned int, in_addr_t> mNextAddressOffsets; + unsigned int mExcludeInterface; +}; + diff --git a/dhcp/server/lease.h b/dhcp/server/lease.h new file mode 100644 index 00000000..bad56147 --- /dev/null +++ b/dhcp/server/lease.h @@ -0,0 +1,67 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <linux/if_ether.h> +#include <stdint.h> + +#include <functional> + +// A lease consists of both the interface index and the MAC address. This +// way the server can run on many different interfaces that have the same +// client MAC address without giving out the same IP address. The reason +// this is useful is because we might have several virtual interfaces, one +// for each access point, that all have the same endpoint on the other side. +// This endpoint would then have the same MAC address and always get the +// same address. But for routing purposes it's useful to give it different +// addresses depending on the server side interface. That way the routing +// table can be set up so that packets are forwarded to the correct access +// point interface based on IP address. +struct Lease { + Lease(unsigned int interfaceIndex, const uint8_t* macAddress) { + InterfaceIndex = interfaceIndex; + memcpy(MacAddress, macAddress, sizeof(MacAddress)); + } + unsigned int InterfaceIndex; + uint8_t MacAddress[ETH_ALEN]; +}; + +template<class T> +inline void hash_combine(size_t& seed, const T& value) { + std::hash<T> hasher; + seed ^= hasher(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +namespace std { +template<> struct hash<Lease> { + size_t operator()(const Lease& lease) const { + size_t seed = 0; + hash_combine(seed, lease.InterfaceIndex); + // Treat the first 4 bytes as an uint32_t to save some computation + hash_combine(seed, *reinterpret_cast<const uint32_t*>(lease.MacAddress)); + // And the remaining 2 bytes as an uint16_t + hash_combine(seed, + *reinterpret_cast<const uint16_t*>(lease.MacAddress + 4)); + return seed; + } +}; +} + +inline bool operator==(const Lease& left, const Lease& right) { + return left.InterfaceIndex == right.InterfaceIndex && + memcmp(left.MacAddress, right.MacAddress, sizeof(left.MacAddress)) == 0; +} diff --git a/network/wifi_forwarder/log.h b/dhcp/server/log.h index edadc43b..a0f21e08 100644 --- a/network/wifi_forwarder/log.h +++ b/dhcp/server/log.h @@ -1,11 +1,11 @@ /* - * Copyright 2018, The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #pragma once -#define LOG_TAG "wifi_forwarder" +#define LOG_TAG "dhcpserver" #include <log/log.h> + diff --git a/dhcp/server/main.cpp b/dhcp/server/main.cpp new file mode 100644 index 00000000..482ffd61 --- /dev/null +++ b/dhcp/server/main.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dhcpserver.h" + +#include "log.h" + +#include <arpa/inet.h> +#include <net/if.h> + +static void usage(const char* program) { + ALOGE("Usage: %s -i <interface> -r <", program); +} + +int main(int argc, char* argv[]) { + char* excludeInterfaceName = nullptr; + unsigned int excludeInterfaceIndex = 0; + for (int i = 1; i < argc; ++i) { + if (strcmp("--exclude-interface", argv[i]) == 0) { + if (i + 1 >= argc) { + ALOGE("ERROR: Missing argument to " + "--exclude-interfaces parameter"); + usage(argv[0]); + return 1; + } + excludeInterfaceName = argv[i + 1]; + excludeInterfaceIndex = if_nametoindex(excludeInterfaceName); + if (excludeInterfaceIndex == 0) { + ALOGE("ERROR: Invalid argument '%s' to --exclude-interface", + argv[i + 1]); + usage(argv[0]); + return 1; + } + } + } + + DhcpServer server(excludeInterfaceIndex); + Result res = server.init(); + if (!res) { + ALOGE("Failed to initialize DHCP server: %s\n", res.c_str()); + return 1; + } + + res = server.run(); + if (!res) { + ALOGE("DHCP server failed: %s\n", res.c_str()); + return 1; + } + // This is weird and shouldn't happen, the server should run forever. + return 0; +} + + diff --git a/emulator-info.txt b/emulator-info.txt index f35794e4..6058b939 100644 --- a/emulator-info.txt +++ b/emulator-info.txt @@ -1,2 +1,2 @@ # Emulator (stable) version -require version-emulator=5971124 +require version-emulator=5513838 diff --git a/fingerprint/fingerprint.c b/fingerprint/fingerprint.c index 507fe13d..8b54c11a 100644 --- a/fingerprint/fingerprint.c +++ b/fingerprint/fingerprint.c @@ -123,7 +123,7 @@ static void saveFingerprint(worker_thread_t* listener, int idx) { return; } int nf = fwrite(&listener->fingerid[idx], sizeof(uint64_t), 1, fp); - if (ns != 1 || nf !=1) + if (ns != 1 || ns !=1) ALOGW("Corrupt emulator fingerprints storage; could not save " "fingerprints"); diff --git a/fstab.goldfish b/fstab.goldfish index c626f400..cecc0471 100644 --- a/fstab.goldfish +++ b/fstab.goldfish @@ -4,4 +4,5 @@ # specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK /dev/block/mtdblock0 /system ext4 ro,barrier=1 wait /dev/block/mtdblock1 /data ext4 noatime,nosuid,nodev,barrier=1,nomblk_io_submit wait,check +/dev/block/mtdblock2 /cache ext4 noatime,nosuid,nodev wait,check /devices/platform/goldfish_mmc.0* auto auto defaults voldmanaged=sdcard:auto,encryptable=userdata diff --git a/fstab.ranchu b/fstab.ranchu index f4e46e8c..5fcd5cec 100644 --- a/fstab.ranchu +++ b/fstab.ranchu @@ -3,6 +3,5 @@ system /system ext4 ro,barrier=1 wait,logical,avb=vbmeta,first_stage_mount vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount /dev/block/vdc /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,check,quota,fileencryption=aes-256-xts:aes-256-cts,reservedsize=128M -/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount /devices/*/block/vdf auto auto defaults voldmanaged=sdcard:auto,encryptable=userdata dev/block/zram0 none swap defaults zramsize=75% diff --git a/fstab.ranchu.arm.ex b/fstab.ranchu.arm.ex deleted file mode 100644 index 9946b6aa..00000000 --- a/fstab.ranchu.arm.ex +++ /dev/null @@ -1,10 +0,0 @@ -# Android fstab file. -#<src> <mnt_point> <type> <mnt_flags and options> <fs_mgr_flags> -# The filesystem that contains the filesystem checker binary (typically /system) cannot -# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK -system /system ext4 ro,barrier=1 wait,logical,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -product /product ext4 ro,barrier=1 wait,logical,first_stage_mount -system_ext /system_ext ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/vdc /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,check,quota -/devices/*/block/vde auto auto defaults voldmanaged=sdcard:auto,encryptable=userdata diff --git a/fstab.ranchu.ex b/fstab.ranchu.ex deleted file mode 100644 index 9dc7eb36..00000000 --- a/fstab.ranchu.ex +++ /dev/null @@ -1,10 +0,0 @@ -# Android fstab file. -#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> -system /system ext4 ro,barrier=1 wait,logical,avb=vbmeta,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -product /product ext4 ro,barrier=1 wait,logical,first_stage_mount -system_ext /system_ext ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/vdc /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,check,quota,fileencryption=aes-256-xts:aes-256-cts,reservedsize=128M -/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount -/devices/*/block/vdf auto auto defaults voldmanaged=sdcard:auto,encryptable=userdata -dev/block/zram0 none swap defaults zramsize=75% diff --git a/fstab.ranchu.initrd b/fstab.ranchu.initrd index c3799601..e792febb 100644 --- a/fstab.ranchu.initrd +++ b/fstab.ranchu.initrd @@ -2,4 +2,3 @@ #<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> system /system ext4 ro,barrier=1 wait,logical,avb=vbmeta,first_stage_mount vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount diff --git a/fstab.ranchu.initrd.arm.ex b/fstab.ranchu.initrd.arm.ex deleted file mode 100644 index d9398413..00000000 --- a/fstab.ranchu.initrd.arm.ex +++ /dev/null @@ -1,6 +0,0 @@ -# Android fstab file. -#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> -system /system ext4 ro,barrier=1 wait,logical,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -product /product ext4 ro,barrier=1 wait,logical,first_stage_mount -system_ext /system_ext ext4 ro,barrier=1 wait,logical,first_stage_mount diff --git a/fstab.ranchu.initrd.ex b/fstab.ranchu.initrd.ex deleted file mode 100644 index 971d83a0..00000000 --- a/fstab.ranchu.initrd.ex +++ /dev/null @@ -1,7 +0,0 @@ -# Android fstab file for ramdisk -#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> -system /system ext4 ro,barrier=1 wait,logical,avb=vbmeta,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -product /product ext4 ro,barrier=1 wait,logical,first_stage_mount -system_ext /system_ext ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount diff --git a/fstab.ranchu.initrd.noavb b/fstab.ranchu.initrd.noavb deleted file mode 100644 index 53da533c..00000000 --- a/fstab.ranchu.initrd.noavb +++ /dev/null @@ -1,5 +0,0 @@ -# Android fstab file for ramdisk -#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> -system /system ext4 ro,barrier=1 wait,logical,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount diff --git a/fstab.ranchu.initrd.noavb.ex b/fstab.ranchu.initrd.noavb.ex deleted file mode 100644 index c3be28a7..00000000 --- a/fstab.ranchu.initrd.noavb.ex +++ /dev/null @@ -1,7 +0,0 @@ -# Android fstab file for ramdisk -#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> -system /system ext4 ro,barrier=1 wait,logical,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -product /product ext4 ro,barrier=1 wait,logical,first_stage_mount -system_ext /system_ext ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount diff --git a/fstab.ranchu.noavb b/fstab.ranchu.noavb deleted file mode 100644 index 88e009df..00000000 --- a/fstab.ranchu.noavb +++ /dev/null @@ -1,8 +0,0 @@ -# Android fstab file. -#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> -system /system ext4 ro,barrier=1 wait,logical,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/vdc /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,check,quota,fileencryption=aes-256-xts:aes-256-cts,reservedsize=128M -/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount -/devices/*/block/vdf auto auto defaults voldmanaged=sdcard:auto,encryptable=userdata -dev/block/zram0 none swap defaults zramsize=75% diff --git a/fstab.ranchu.noavb.ex b/fstab.ranchu.noavb.ex deleted file mode 100644 index 7b4b921f..00000000 --- a/fstab.ranchu.noavb.ex +++ /dev/null @@ -1,10 +0,0 @@ -# Android fstab file. -#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> -system /system ext4 ro,barrier=1 wait,logical,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -product /product ext4 ro,barrier=1 wait,logical,first_stage_mount -system_ext /system_ext ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/vdc /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,check,quota,fileencryption=aes-256-xts:aes-256-cts,reservedsize=128M -/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount -/devices/*/block/vdf auto auto defaults voldmanaged=sdcard:auto,encryptable=userdata -dev/block/zram0 none swap defaults zramsize=75% diff --git a/fvp.mk b/fvp.mk deleted file mode 100644 index f403230d..00000000 --- a/fvp.mk +++ /dev/null @@ -1,103 +0,0 @@ -# -# Copyright 2019 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -PRODUCT_USE_DYNAMIC_PARTITIONS := true -PRODUCT_FULL_TREBLE_OVERRIDE := true - -# -# All components inherited here go to system image -# -$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk) -$(call inherit-product, $(SRC_TARGET_DIR)/product/mainline_system.mk) - -PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \ - root/init.zygote64_32.rc \ - -# -# All components inherited here go to product image -# -$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_product.mk) - -# -# All components inherited here go to vendor image -# -$(call inherit-product, $(SRC_TARGET_DIR)/product/media_vendor.mk) - -PRODUCT_PACKAGES += \ - android.hardware.audio@2.0-service \ - android.hardware.audio@4.0-impl:32 \ - android.hardware.audio.effect@4.0-impl:32 \ - android.hardware.drm@1.0-service \ - android.hardware.drm@1.0-impl \ - android.hardware.drm@1.2-service.clearkey \ - android.hardware.gatekeeper@1.0-service.software \ - android.hardware.graphics.allocator@2.0-service \ - android.hardware.graphics.allocator@2.0-impl \ - android.hardware.graphics.composer@2.1-service \ - android.hardware.graphics.composer@2.1-impl \ - android.hardware.graphics.mapper@2.0-impl \ - android.hardware.health@2.0-service.goldfish \ - android.hardware.keymaster@4.0-service \ - android.hardware.keymaster@4.0-impl \ - libEGL_swiftshader \ - libGLESv1_CM_swiftshader \ - libGLESv2_swiftshader \ - -PRODUCT_PACKAGE_OVERLAYS := device/generic/goldfish/overlay - -PRODUCT_NAME := fvp -PRODUCT_DEVICE := fvpbase -PRODUCT_BRAND := Android -PRODUCT_MODEL := AOSP on FVP - -PRODUCT_COPY_FILES += \ - device/generic/goldfish/data/etc/handheld_core_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/handheld_core_hardware.xml \ - frameworks/native/data/etc/android.hardware.ethernet.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.ethernet.xml \ - device/generic/goldfish/fvpbase/fstab.fvpbase:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.fvpbase \ - device/generic/goldfish/fvpbase/fstab.fvpbase.initrd:$(TARGET_COPY_OUT_RAMDISK)/fstab.fvpbase \ - device/generic/goldfish/fvpbase/init.fvpbase.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.fvpbase.rc \ - device/generic/goldfish/fvpbase/init.insmod.sh:$(TARGET_COPY_OUT_VENDOR)/bin/init.insmod.sh \ - frameworks/av/services/audiopolicy/config/audio_policy_configuration_generic.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml \ - frameworks/av/services/audiopolicy/config/primary_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/primary_audio_policy_configuration.xml \ - frameworks/av/services/audiopolicy/config/r_submix_audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/r_submix_audio_policy_configuration.xml \ - frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_volumes.xml \ - frameworks/av/services/audiopolicy/config/default_volume_tables.xml:$(TARGET_COPY_OUT_VENDOR)/etc/default_volume_tables.xml \ - frameworks/av/services/audiopolicy/config/surround_sound_configuration_5_0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/surround_sound_configuration_5_0.xml \ - -PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \ - ro.hardware.egl=swiftshader \ - debug.sf.nobootanimation=1 \ - -PRODUCT_REQUIRES_INSECURE_EXECMEM_FOR_SWIFTSHADER := true - -# It's almost always faster to dexopt on the host even in eng builds. -WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY := false - -BOARD_VENDOR_KERNEL_MODULES := \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/amba-clcd.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/ambakmi.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/armmmci.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/cfbcopyarea.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/cfbfillrect.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/cfbimgblt.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/fb.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/fixed.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/mmc_block.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/mmc_core.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/mousedev.ko \ - $(OUT_DIR)/target/product/$(PRODUCT_DEVICE)/boot/psmouse.ko - -DEVICE_MANIFEST_FILE := device/generic/goldfish/fvpbase/manifest.xml diff --git a/fvpbase/BoardConfig.mk b/fvpbase/BoardConfig.mk deleted file mode 100644 index 234645e7..00000000 --- a/fvpbase/BoardConfig.mk +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (C) 2019 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -TARGET_ARCH := arm64 -TARGET_ARCH_VARIANT := armv8-a -TARGET_CPU_VARIANT := generic -TARGET_CPU_ABI := arm64-v8a - -TARGET_2ND_ARCH := arm -TARGET_2ND_CPU_ABI := armeabi-v7a -TARGET_2ND_CPU_ABI2 := armeabi -TARGET_2ND_ARCH_VARIANT := armv8-a -TARGET_2ND_CPU_VARIANT := generic - -include build/make/target/board/BoardConfigMainlineCommon.mk - -TARGET_NO_KERNEL := true - -BOARD_USES_SYSTEM_OTHER_ODEX := - -BUILD_QEMU_IMAGES := true -TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true - -BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true - -BOARD_SUPER_PARTITION_SIZE := 3229614080 -BOARD_SUPER_PARTITION_GROUPS := fvp_dynamic_partitions -BOARD_FVP_DYNAMIC_PARTITIONS_SIZE := 3221225472 -BOARD_FVP_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor -TARGET_COPY_OUT_PRODUCT := system/product -TARGET_COPY_OUT_SYSTEM_EXT := system/system_ext - -BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4 - -BOARD_USERDATAIMAGE_PARTITION_SIZE := 576716800 - -BOARD_SEPOLICY_DIRS += device/generic/goldfish/fvpbase/sepolicy - -TARGET_EXPERIMENTAL_MTE := true diff --git a/fvpbase/fstab.fvpbase b/fvpbase/fstab.fvpbase deleted file mode 100644 index 6c62809c..00000000 --- a/fvpbase/fstab.fvpbase +++ /dev/null @@ -1,8 +0,0 @@ -# Android fstab file. -#<src> <mnt_point> <type> <mnt_flags and options> <fs_mgr_flags> -# The filesystem that contains the filesystem checker binary (typically /system) cannot -# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK -system /system ext4 ro,barrier=1 wait,logical,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount -/dev/block/mmcblk0 /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,check,quota -/devices/*/block/vde auto auto defaults voldmanaged=sdcard:auto,encryptable=userdata diff --git a/fvpbase/fstab.fvpbase.initrd b/fvpbase/fstab.fvpbase.initrd deleted file mode 100644 index 56056634..00000000 --- a/fvpbase/fstab.fvpbase.initrd +++ /dev/null @@ -1,4 +0,0 @@ -# Android fstab file. -#<dev> <mnt_point> <type> <mnt_flags options> <fs_mgr_flags> -system /system ext4 ro,barrier=1 wait,logical,first_stage_mount -vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount diff --git a/fvpbase/init.fvpbase.rc b/fvpbase/init.fvpbase.rc deleted file mode 100644 index 41b6d7cf..00000000 --- a/fvpbase/init.fvpbase.rc +++ /dev/null @@ -1,12 +0,0 @@ -service insmod_sh /vendor/bin/init.insmod.sh - user root - group root system - disabled - oneshot - -on init - start insmod_sh - -on fs - wait_for_prop vendor.all.modules.ready 1 - mount_all /vendor/etc/fstab.fvpbase diff --git a/fvpbase/init.insmod.sh b/fvpbase/init.insmod.sh deleted file mode 100644 index f06a3827..00000000 --- a/fvpbase/init.insmod.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/vendor/bin/sh -e - -insmod /vendor/lib/modules/fb.ko -insmod /vendor/lib/modules/cfbcopyarea.ko -insmod /vendor/lib/modules/cfbfillrect.ko -insmod /vendor/lib/modules/cfbimgblt.ko -insmod /vendor/lib/modules/amba-clcd.ko - -insmod /vendor/lib/modules/fixed.ko -insmod /vendor/lib/modules/mmc_core.ko -insmod /vendor/lib/modules/mmc_block.ko -insmod /vendor/lib/modules/armmmci.ko - -insmod /vendor/lib/modules/ambakmi.ko -insmod /vendor/lib/modules/mousedev.ko -insmod /vendor/lib/modules/psmouse.ko - -setprop vendor.all.modules.ready 1 diff --git a/fvpbase/manifest.xml b/fvpbase/manifest.xml deleted file mode 100644 index bd369aee..00000000 --- a/fvpbase/manifest.xml +++ /dev/null @@ -1,102 +0,0 @@ -<manifest version="1.0" type="device" target-level="3"> - <hal format="hidl"> - <name>android.hardware.audio</name> - <transport>hwbinder</transport> - <version>4.0</version> - <interface> - <name>IDevicesFactory</name> - <instance>default</instance> - </interface> - </hal> - <hal format="hidl"> - <name>android.hardware.audio.effect</name> - <transport>hwbinder</transport> - <version>4.0</version> - <interface> - <name>IEffectsFactory</name> - <instance>default</instance> - </interface> - </hal> - <hal format="hidl"> - <name>android.hardware.configstore</name> - <transport>hwbinder</transport> - <version>1.1</version> - <interface> - <name>ISurfaceFlingerConfigs</name> - <instance>default</instance> - </interface> - </hal> - <hal format="hidl"> - <name>android.hardware.drm</name> - <transport>hwbinder</transport> - <version>1.0</version> - <interface> - <name>ICryptoFactory</name> - <instance>default</instance> - </interface> - <interface> - <name>IDrmFactory</name> - <instance>default</instance> - </interface> - <fqname>@1.2::ICryptoFactory/clearkey</fqname> - <fqname>@1.2::IDrmFactory/clearkey</fqname> - </hal> - <hal format="hidl"> - <name>android.hardware.graphics.allocator</name> - <transport>hwbinder</transport> - <version>2.0</version> - <interface> - <name>IAllocator</name> - <instance>default</instance> - </interface> - </hal> - <hal format="hidl"> - <name>android.hardware.graphics.composer</name> - <transport>hwbinder</transport> - <version>2.1</version> - <interface> - <name>IComposer</name> - <instance>default</instance> - </interface> - </hal> - <hal format="hidl"> - <name>android.hardware.graphics.mapper</name> - <transport arch="32+64">passthrough</transport> - <version>2.0</version> - <interface> - <name>IMapper</name> - <instance>default</instance> - </interface> - </hal> - <hal format="hidl"> - <name>android.hardware.health</name> - <transport>hwbinder</transport> - <version>2.0</version> - <interface> - <name>IHealth</name> - <instance>default</instance> - </interface> - </hal> - <hal format="hidl"> - <name>android.hardware.keymaster</name> - <transport>hwbinder</transport> - <version>4.0</version> - <interface> - <name>IKeymasterDevice</name> - <instance>default</instance> - </interface> - </hal> - <hal format="hidl"> - <name>android.hardware.media.omx</name> - <transport>hwbinder</transport> - <version>1.0</version> - <interface> - <name>IOmx</name> - <instance>default</instance> - </interface> - <interface> - <name>IOmxStore</name> - <instance>default</instance> - </interface> - </hal> -</manifest> diff --git a/fvpbase/sepolicy/file.te b/fvpbase/sepolicy/file.te deleted file mode 100644 index b3bd582b..00000000 --- a/fvpbase/sepolicy/file.te +++ /dev/null @@ -1 +0,0 @@ -type varrun_file, file_type, data_file_type, mlstrustedobject; diff --git a/fvpbase/sepolicy/file_contexts b/fvpbase/sepolicy/file_contexts deleted file mode 100644 index 29ff279c..00000000 --- a/fvpbase/sepolicy/file_contexts +++ /dev/null @@ -1,8 +0,0 @@ -/data/vendor/var/run(/.*)? u:object_r:varrun_file:s0 -/dev/block/mmcblk0 u:object_r:userdata_block_device:s0 -/vendor/bin/hw/android\.hardware\.gatekeeper@1\.0-service.software u:object_r:hal_gatekeeper_default_exec:s0 -/vendor/bin/hw/android\.hardware\.health@2\.0-service.goldfish u:object_r:hal_health_default_exec:s0 -/vendor/bin/init\.insmod\.sh u:object_r:init_insmod_sh_exec:s0 -/vendor/lib(64)?/libEGL_swiftshader\.so u:object_r:same_process_hal_file:s0 -/vendor/lib(64)?/libGLESv1_CM_swiftshader\.so u:object_r:same_process_hal_file:s0 -/vendor/lib(64)?/libGLESv2_swiftshader\.so u:object_r:same_process_hal_file:s0 diff --git a/fvpbase/sepolicy/hal_graphics_allocator_default.te b/fvpbase/sepolicy/hal_graphics_allocator_default.te deleted file mode 100644 index 6676f578..00000000 --- a/fvpbase/sepolicy/hal_graphics_allocator_default.te +++ /dev/null @@ -1,4 +0,0 @@ -allow hal_graphics_allocator_default graphics_device:dir search; -allow hal_graphics_allocator_default graphics_device:chr_file { ioctl open read write map rw_file_perms }; -allow hal_graphics_allocator_default dumpstate:fd use; -allow hal_graphics_allocator_default dumpstate:fifo_file write; diff --git a/fvpbase/sepolicy/healthd.te b/fvpbase/sepolicy/healthd.te deleted file mode 100644 index 80db9b72..00000000 --- a/fvpbase/sepolicy/healthd.te +++ /dev/null @@ -1,4 +0,0 @@ -# Allow to read /sys/class/power_supply directory -allow healthd sysfs:dir r_dir_perms; - -allow healthd self:capability2 wake_alarm; diff --git a/fvpbase/sepolicy/init_insmod_sh.te b/fvpbase/sepolicy/init_insmod_sh.te deleted file mode 100644 index 52a0ad84..00000000 --- a/fvpbase/sepolicy/init_insmod_sh.te +++ /dev/null @@ -1,14 +0,0 @@ -type init_insmod_sh, domain; -type init_insmod_sh_exec, exec_type, vendor_file_type, file_type; - -init_daemon_domain(init_insmod_sh) - -allow init_insmod_sh vendor_shell_exec:file rx_file_perms; -allow init_insmod_sh vendor_toolbox_exec:file rx_file_perms; - -# Set the vendor.all.modules.ready property -set_prop(init_insmod_sh, vendor_device_prop) - -# Allow insmod -allow init_insmod_sh self:capability sys_module; -allow init_insmod_sh vendor_file:system module_load; diff --git a/fvpbase/sepolicy/property.te b/fvpbase/sepolicy/property.te deleted file mode 100644 index f014ad52..00000000 --- a/fvpbase/sepolicy/property.te +++ /dev/null @@ -1 +0,0 @@ -type vendor_device_prop, property_type; diff --git a/fvpbase/sepolicy/property_contexts b/fvpbase/sepolicy/property_contexts deleted file mode 100644 index c389bdd3..00000000 --- a/fvpbase/sepolicy/property_contexts +++ /dev/null @@ -1 +0,0 @@ -vendor.all.modules.ready u:object_r:vendor_device_prop:s0 diff --git a/fvpbase/sepolicy/surfaceflinger.te b/fvpbase/sepolicy/surfaceflinger.te deleted file mode 100644 index 95236305..00000000 --- a/fvpbase/sepolicy/surfaceflinger.te +++ /dev/null @@ -1 +0,0 @@ -allow surfaceflinger self:process execmem; diff --git a/gatekeeper/Android.mk b/gatekeeper/Android.mk new file mode 100644 index 00000000..0cb2c150 --- /dev/null +++ b/gatekeeper/Android.mk @@ -0,0 +1,45 @@ +# +# Copyright (C) 2015 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE := gatekeeper.ranchu +LOCAL_MODULE_RELATIVE_PATH := hw + +LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused +LOCAL_SRC_FILES := \ + module.cpp \ + SoftGateKeeperDevice.cpp + + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libgatekeeper \ + liblog \ + libhardware \ + libbase \ + libutils \ + libcrypto \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + android.hardware.gatekeeper@1.0 \ + +LOCAL_STATIC_LIBRARIES := libscrypt_static +LOCAL_C_INCLUDES := external/scrypt/lib/crypto +include $(BUILD_SHARED_LIBRARY) diff --git a/gatekeeper/SoftGateKeeper.h b/gatekeeper/SoftGateKeeper.h new file mode 100644 index 00000000..2f4f4d7e --- /dev/null +++ b/gatekeeper/SoftGateKeeper.h @@ -0,0 +1,182 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SOFT_GATEKEEPER_H_ +#define SOFT_GATEKEEPER_H_ + +extern "C" { +#include <openssl/rand.h> +#include <openssl/sha.h> + +#include <crypto_scrypt.h> +} + +#include <android-base/memory.h> +#include <gatekeeper/gatekeeper.h> + +#include <iostream> +#include <unordered_map> +#include <memory> + +namespace gatekeeper { + +struct fast_hash_t { + uint64_t salt; + uint8_t digest[SHA256_DIGEST_LENGTH]; +}; + +class SoftGateKeeper : public GateKeeper { +public: + static const uint32_t SIGNATURE_LENGTH_BYTES = 32; + + // scrypt params + static const uint64_t N = 16384; + static const uint32_t r = 8; + static const uint32_t p = 1; + + static const int MAX_UINT_32_CHARS = 11; + + SoftGateKeeper() { + key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]); + memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES); + } + + virtual ~SoftGateKeeper() { + } + + virtual bool GetAuthTokenKey(const uint8_t **auth_token_key, + uint32_t *length) const { + if (auth_token_key == NULL || length == NULL) return false; + uint8_t *auth_token_key_copy = new uint8_t[SIGNATURE_LENGTH_BYTES]; + memcpy(auth_token_key_copy, key_.get(), SIGNATURE_LENGTH_BYTES); + + *auth_token_key = auth_token_key_copy; + *length = SIGNATURE_LENGTH_BYTES; + return true; + } + + virtual void GetPasswordKey(const uint8_t **password_key, uint32_t *length) { + if (password_key == NULL || length == NULL) return; + uint8_t *password_key_copy = new uint8_t[SIGNATURE_LENGTH_BYTES]; + memcpy(password_key_copy, key_.get(), SIGNATURE_LENGTH_BYTES); + + *password_key = password_key_copy; + *length = SIGNATURE_LENGTH_BYTES; + } + + virtual void ComputePasswordSignature(uint8_t *signature, uint32_t signature_length, + const uint8_t *, uint32_t, const uint8_t *password, + uint32_t password_length, salt_t salt) const { + if (signature == NULL) return; + crypto_scrypt(password, password_length, reinterpret_cast<uint8_t *>(&salt), + sizeof(salt), N, r, p, signature, signature_length); + } + + virtual void GetRandom(void *random, uint32_t requested_length) const { + if (random == NULL) return; + RAND_pseudo_bytes((uint8_t *) random, requested_length); + } + + virtual void ComputeSignature(uint8_t *signature, uint32_t signature_length, + const uint8_t *, uint32_t, const uint8_t *, const uint32_t) const { + if (signature == NULL) return; + memset(signature, 0, signature_length); + } + + virtual uint64_t GetMillisecondsSinceBoot() const { + struct timespec time; + int res = clock_gettime(CLOCK_BOOTTIME, &time); + if (res < 0) return 0; + return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000); + } + + virtual bool IsHardwareBacked() const { + return false; + } + + virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t *record, + bool /* secure */) { + failure_record_t *stored = &failure_map_[uid]; + if (user_id != stored->secure_user_id) { + stored->secure_user_id = user_id; + stored->last_checked_timestamp = 0; + stored->failure_counter = 0; + } + memcpy(record, stored, sizeof(*record)); + return true; + } + + virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) { + failure_record_t *stored = &failure_map_[uid]; + stored->secure_user_id = user_id; + stored->last_checked_timestamp = 0; + stored->failure_counter = 0; + return true; + } + + virtual bool WriteFailureRecord(uint32_t uid, failure_record_t *record, bool /* secure */) { + failure_map_[uid] = *record; + return true; + } + + fast_hash_t ComputeFastHash(const SizedBuffer &password, uint64_t salt) { + fast_hash_t fast_hash; + size_t digest_size = password.length + sizeof(salt); + std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]); + memcpy(digest.get(), &salt, sizeof(salt)); + memcpy(digest.get() + sizeof(salt), password.buffer.get(), password.length); + + SHA256(digest.get(), digest_size, (uint8_t *) &fast_hash.digest); + + fast_hash.salt = salt; + return fast_hash; + } + + bool VerifyFast(const fast_hash_t &fast_hash, const SizedBuffer &password) { + fast_hash_t computed = ComputeFastHash(password, fast_hash.salt); + return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0; + } + + bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) { + uint64_t user_id = android::base::get_unaligned<secure_id_t>(&expected_handle->user_id); + FastHashMap::const_iterator it = fast_hash_map_.find(user_id); + if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) { + return true; + } else { + if (GateKeeper::DoVerify(expected_handle, password)) { + uint64_t salt; + GetRandom(&salt, sizeof(salt)); + fast_hash_map_[user_id] = ComputeFastHash(password, salt); + return true; + } + } + + return false; + } + +private: + + typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap; + typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap; + + std::unique_ptr<uint8_t[]> key_; + FailureRecordMap failure_map_; + FastHashMap fast_hash_map_; +}; +} + +#endif // SOFT_GATEKEEPER_H_ diff --git a/gatekeeper/SoftGateKeeperDevice.cpp b/gatekeeper/SoftGateKeeperDevice.cpp new file mode 100644 index 00000000..3dc69977 --- /dev/null +++ b/gatekeeper/SoftGateKeeperDevice.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "SoftGateKeeper.h" +#include "SoftGateKeeperDevice.h" + +namespace goldfish { + +int SoftGateKeeperDevice::enroll(uint32_t uid, + const uint8_t *current_password_handle, uint32_t current_password_handle_length, + const uint8_t *current_password, uint32_t current_password_length, + const uint8_t *desired_password, uint32_t desired_password_length, + uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) { + + if (enrolled_password_handle == NULL || enrolled_password_handle_length == NULL || + desired_password == NULL || desired_password_length == 0) + return -EINVAL; + + // Current password and current password handle go together + if (current_password_handle == NULL || current_password_handle_length == 0 || + current_password == NULL || current_password_length == 0) { + current_password_handle = NULL; + current_password_handle_length = 0; + current_password = NULL; + current_password_length = 0; + } + + SizedBuffer desired_password_buffer(desired_password_length); + memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length); + + SizedBuffer current_password_handle_buffer(current_password_handle_length); + if (current_password_handle) { + memcpy(current_password_handle_buffer.buffer.get(), current_password_handle, + current_password_handle_length); + } + + SizedBuffer current_password_buffer(current_password_length); + if (current_password) { + memcpy(current_password_buffer.buffer.get(), current_password, current_password_length); + } + + EnrollRequest request(uid, ¤t_password_handle_buffer, &desired_password_buffer, + ¤t_password_buffer); + EnrollResponse response; + + impl_->Enroll(request, &response); + + if (response.error == ERROR_RETRY) { + return response.retry_timeout; + } else if (response.error != ERROR_NONE) { + return -EINVAL; + } + + *enrolled_password_handle = response.enrolled_password_handle.buffer.release(); + gatekeeper::password_handle_t *handle = + reinterpret_cast<gatekeeper::password_handle_t *>(*enrolled_password_handle); + //FIXIT: We need to move this module to host with gatekeeper pipe + handle->hardware_backed = true; + + *enrolled_password_handle_length = response.enrolled_password_handle.length; + return 0; +} + +int SoftGateKeeperDevice::verify(uint32_t uid, + uint64_t challenge, const uint8_t *enrolled_password_handle, + uint32_t enrolled_password_handle_length, const uint8_t *provided_password, + uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length, + bool *request_reenroll) { + + if (enrolled_password_handle == NULL || + provided_password == NULL) { + return -EINVAL; + } + + SizedBuffer password_handle_buffer(enrolled_password_handle_length); + memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle, + enrolled_password_handle_length); + SizedBuffer provided_password_buffer(provided_password_length); + memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length); + + VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer); + VerifyResponse response; + + impl_->Verify(request, &response); + + if (response.error == ERROR_RETRY) { + return response.retry_timeout; + } else if (response.error != ERROR_NONE) { + return -EINVAL; + } + + if (auth_token != NULL && auth_token_length != NULL) { + *auth_token = response.auth_token.buffer.release(); + *auth_token_length = response.auth_token.length; + } + + if (request_reenroll != NULL) { + *request_reenroll = response.request_reenroll; + } + + return 0; +} + +} // namespace goldfish diff --git a/gatekeeper/SoftGateKeeperDevice.h b/gatekeeper/SoftGateKeeperDevice.h new file mode 100644 index 00000000..af3a1bc5 --- /dev/null +++ b/gatekeeper/SoftGateKeeperDevice.h @@ -0,0 +1,76 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SOFT_GATEKEEPER_DEVICE_H_ +#define SOFT_GATEKEEPER_DEVICE_H_ + +#include "SoftGateKeeper.h" + +#include <memory> + +using namespace gatekeeper; + +namespace goldfish { + +/** + * Software based GateKeeper implementation + */ +class SoftGateKeeperDevice { +public: + SoftGateKeeperDevice() { + impl_.reset(new SoftGateKeeper()); + } + + // Wrappers to translate the gatekeeper HAL API to the Kegyuard Messages API. + + /** + * Enrolls password_payload, which should be derived from a user selected pin or password, + * with the authentication factor private key used only for enrolling authentication + * factor data. + * + * Returns: 0 on success or an error code less than 0 on error. + * On error, enrolled_password_handle will not be allocated. + */ + int enroll(uint32_t uid, + const uint8_t *current_password_handle, uint32_t current_password_handle_length, + const uint8_t *current_password, uint32_t current_password_length, + const uint8_t *desired_password, uint32_t desired_password_length, + uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length); + + /** + * Verifies provided_password matches enrolled_password_handle. + * + * Implementations of this module may retain the result of this call + * to attest to the recency of authentication. + * + * On success, writes the address of a verification token to auth_token, + * usable to attest password verification to other trusted services. Clients + * may pass NULL for this value. + * + * Returns: 0 on success or an error code less than 0 on error + * On error, verification token will not be allocated + */ + int verify(uint32_t uid, uint64_t challenge, + const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length, + const uint8_t *provided_password, uint32_t provided_password_length, + uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll); +private: + std::unique_ptr<SoftGateKeeper> impl_; +}; + +} // namespace gatekeeper + +#endif //SOFT_GATEKEEPER_DEVICE_H_ diff --git a/gatekeeper/module.cpp b/gatekeeper/module.cpp new file mode 100644 index 00000000..3bcfe15a --- /dev/null +++ b/gatekeeper/module.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <hardware/hardware.h> +#include <hardware/gatekeeper.h> +#define LOG_TAG "GoldfishGatekeeper" +#include <log/log.h> + +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +#include "SoftGateKeeper.h" +#include "SoftGateKeeperDevice.h" + +using goldfish::SoftGateKeeperDevice; + +struct goldfish_gatekeeper_device { + gatekeeper_device device; + SoftGateKeeperDevice *s_gatekeeper; +}; + +static goldfish_gatekeeper_device s_device; + +static int enroll(const struct gatekeeper_device *dev __unused, uint32_t uid, + const uint8_t *current_password_handle, uint32_t current_password_handle_length, + const uint8_t *current_password, uint32_t current_password_length, + const uint8_t *desired_password, uint32_t desired_password_length, + uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) { + + SoftGateKeeperDevice *s_gatekeeper = ((goldfish_gatekeeper_device*)(dev))->s_gatekeeper; + ALOGE("called %s with gate keeper %p device %p\n", __func__, s_gatekeeper, dev); + if (s_gatekeeper == nullptr) { + abort(); + return -EINVAL; + } + + return s_gatekeeper->enroll(uid, + current_password_handle, current_password_handle_length, + current_password, current_password_length, + desired_password, desired_password_length, + enrolled_password_handle, enrolled_password_handle_length); +} + +static int verify(const struct gatekeeper_device *dev __unused, uint32_t uid, uint64_t challenge, + const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length, + const uint8_t *provided_password, uint32_t provided_password_length, + uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) { + SoftGateKeeperDevice *s_gatekeeper = ((goldfish_gatekeeper_device*)(dev))->s_gatekeeper; + ALOGE("called %s with gate keeper %p device %p\n", __func__, s_gatekeeper, dev); + if (s_gatekeeper == nullptr) return -EINVAL; + return s_gatekeeper->verify(uid, challenge, + enrolled_password_handle, enrolled_password_handle_length, + provided_password, provided_password_length, + auth_token, auth_token_length, request_reenroll); +} + +static int close_device(hw_device_t* dev __unused) { + SoftGateKeeperDevice *s_gatekeeper = ((goldfish_gatekeeper_device*)(dev))->s_gatekeeper; + if (s_gatekeeper == nullptr) return 0; + delete s_gatekeeper; + s_gatekeeper = nullptr; + ALOGE("called %s with gate keeper %p device %p\n", __func__, s_gatekeeper, dev); + return 0; +} + +static int goldfish_gatekeeper_open(const hw_module_t *module, const char *name, + hw_device_t **device) { + + if (strcmp(name, HARDWARE_GATEKEEPER) != 0) { + abort(); + return -EINVAL; + } + + memset(&s_device, 0, sizeof(s_device)); + + SoftGateKeeperDevice *s_gatekeeper = new SoftGateKeeperDevice(); + if (s_gatekeeper == nullptr) return -ENOMEM; + + s_device.s_gatekeeper = s_gatekeeper; + + s_device.device.common.tag = HARDWARE_DEVICE_TAG; + s_device.device.common.version = 1; + s_device.device.common.module = const_cast<hw_module_t *>(module); + s_device.device.common.close = close_device; + + s_device.device.enroll = enroll; + s_device.device.verify = verify; + s_device.device.delete_user = nullptr; + s_device.device.delete_all_users = nullptr; + + *device = &s_device.device.common; + ALOGE("called %s with gate keeper %p device %p\n", __func__, s_gatekeeper, *device); + + return 0; +} + +static struct hw_module_methods_t gatekeeper_module_methods = { + .open = goldfish_gatekeeper_open, +}; + +struct gatekeeper_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = GATEKEEPER_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = GATEKEEPER_HARDWARE_MODULE_ID, + .name = "Goldfish GateKeeper HAL", + .author = "The Android Open Source Project", + .methods = &gatekeeper_module_methods, + .dso = 0, + .reserved = {} + }, +}; diff --git a/health/Android.bp b/health/Android.bp index 11a7a8dc..aab4fa9e 100644 --- a/health/Android.bp +++ b/health/Android.bp @@ -21,12 +21,10 @@ cc_binary { "libbase", "libcutils", "libhidlbase", + "libhidltransport", + "libhwbinder", "libutils", "android.hardware.health@2.0", ], header_libs: ["libhealthd_headers"], - - overrides: [ - "healthd", - ], } diff --git a/include/qemu_pipe.h b/include/qemu_pipe.h index d585ba12..986c3da2 100644 --- a/include/qemu_pipe.h +++ b/include/qemu_pipe.h @@ -34,7 +34,7 @@ typedef int QEMU_PIPE_HANDLE; #define QEMU_PIPE_INVALID_HANDLE -1 -static __inline__ bool ReadFully(int fd, void* data, size_t byte_count) { +static bool ReadFully(int fd, void* data, size_t byte_count) { uint8_t* p = (uint8_t*)(data); size_t remaining = byte_count; while (remaining > 0) { @@ -46,7 +46,7 @@ static __inline__ bool ReadFully(int fd, void* data, size_t byte_count) { return true; } -static __inline__ bool WriteFully(int fd, const void* data, size_t byte_count) { +static bool WriteFully(int fd, const void* data, size_t byte_count) { const uint8_t* p = (const uint8_t*)(data); size_t remaining = byte_count; while (remaining > 0) { diff --git a/init.ranchu.rc b/init.ranchu.rc index 08a0c816..81bcc227 100644 --- a/init.ranchu.rc +++ b/init.ranchu.rc @@ -20,12 +20,6 @@ on post-fs-data mkdir /data/vendor/var 0755 root root mkdir /data/vendor/var/run 0755 root root mkdir /data/vendor/var/run/netns 0755 root root - start ranchu-net - - chown root root /data/vendor/etc - rm /data/vendor/etc/media_codecs_google_video.xml - symlink /data/vendor/etc/media_codecs_google_video_default.xml /data/vendor/etc/media_codecs_google_video.xml - setprop qemu.mediaprofile.video ${ro.kernel.qemu.mediaprofile.video} on zygote-start # Create the directories used by the Wireless subsystem @@ -39,7 +33,6 @@ on boot setprop debug.hwui.renderer ${ro.kernel.qemu.uirenderer} setprop ro.opengles.version ${ro.kernel.qemu.opengles.version} setprop ro.zygote.disable_gl_preload 1 - setprop dalvik.vm.heapsize 192m setprop dalvik.vm.heapsize ${ro.kernel.qemu.dalvik.vm.heapsize} chown root system /sys/power/wake_lock @@ -60,10 +53,6 @@ service ranchu-setup /vendor/bin/init.ranchu-core.sh group root oneshot -on property:qemu.mediaprofile.video=* - rm /data/vendor/etc/media_codecs_google_video.xml - symlink ${qemu.mediaprofile.video} /data/vendor/etc/media_codecs_google_video.xml - on property:vendor.qemu.timezone=* setprop persist.sys.timezone ${vendor.qemu.timezone} @@ -78,32 +67,33 @@ service ranchu-net /vendor/bin/init.ranchu-net.sh user root group root wakelock wifi oneshot - disabled # Started on post-fs-data + +service ipv6proxy /vendor/bin/execns router /vendor/bin/ipv6proxy -o eth0 -i wlan1,radio0-peer + user root + group root + disabled service emu_hostapd /vendor/bin/execns router /vendor/bin/hostapd_nohidl /data/vendor/wifi/hostapd/hostapd.conf user root group root wifi net_raw net_admin disabled -service netmgr /vendor/bin/execns router /vendor/bin/netmgr --if-prefix wlan1 --bridge eth0,radio0-peer +service dhcpserver /vendor/bin/execns router /vendor/bin/dhcpserver --exclude-interface eth0 user root - group root wifi + group root disabled -service wifi_forwarder /vendor/bin/wifi_forwarder +service netmgr /vendor/bin/execns router /vendor/bin/netmgr --if-prefix wlan1_ --network 192.168.232.9/29 user root group root wifi disabled -service dhcpclient_rtr /vendor/bin/dhcpclient -i radio0 --no-gateway +service dhcpclient_rtr /vendor/bin/execns router /vendor/bin/dhcpclient -i eth0 user root group root disabled -on property:vendor.network.bridged=1 - start dhcpclient_rtr - -service dhcpclient_def /vendor/bin/dhcpclient -i eth0 --no-gateway +service dhcpclient_def /vendor/bin/dhcpclient -i eth0 user root group root disabled @@ -140,9 +130,6 @@ service bugreport /system/bin/dumpstate -d -p -B -z \ keycodes 114 115 116 service wpa_supplicant /vendor/bin/hw/wpa_supplicant -Dnl80211 -iwlan0 -c/vendor/etc/wifi/wpa_supplicant.conf -g@android:wpa_wlan0 - interface android.hardware.wifi.supplicant@1.0::ISupplicant default - interface android.hardware.wifi.supplicant@1.1::ISupplicant default - interface android.hardware.wifi.supplicant@1.2::ISupplicant default socket wpa_wlan0 dgram 660 wifi wifi group system wifi inet oneshot diff --git a/input-mt/virtio_input_multi_touch_1.idc b/input-mt/virtio_input_multi_touch_1.idc deleted file mode 100644 index f740c047..00000000 --- a/input-mt/virtio_input_multi_touch_1.idc +++ /dev/null @@ -1,7 +0,0 @@ -device.internal = 1 - -touch.deviceType = touchScreen -touch.orientationAware = 1 - -cursor.mode = navigation -cursor.orientationAware = 1 diff --git a/input-mt/virtio_input_multi_touch_2.idc b/input-mt/virtio_input_multi_touch_2.idc deleted file mode 100644 index 8e1b02ab..00000000 --- a/input-mt/virtio_input_multi_touch_2.idc +++ /dev/null @@ -1,12 +0,0 @@ -device.internal = 1 - -touch.deviceType = touchScreen -touch.orientationAware = 1 - -cursor.mode = navigation -cursor.orientationAware = 1 - -# This displayID matches the unique ID of the virtual display created for Emulator. -# This will indicate to input flinger than it should link this input device -# with the virtual display. -touch.displayId = local:8140900251843329 diff --git a/input-mt/virtio_input_multi_touch_3.idc b/input-mt/virtio_input_multi_touch_3.idc deleted file mode 100644 index 6a112404..00000000 --- a/input-mt/virtio_input_multi_touch_3.idc +++ /dev/null @@ -1,12 +0,0 @@ -device.internal = 1 - -touch.deviceType = touchScreen -touch.orientationAware = 1 - -cursor.mode = navigation -cursor.orientationAware = 1 - -# This displayID matches the unique ID of the virtual display created for Emulator. -# This will indicate to input flinger than it should link this input device -# with the virtual display. -touch.displayId = local:8140940453066754 diff --git a/input-mt/virtio_input_multi_touch_4.idc b/input-mt/virtio_input_multi_touch_4.idc deleted file mode 100644 index 33302f5b..00000000 --- a/input-mt/virtio_input_multi_touch_4.idc +++ /dev/null @@ -1,12 +0,0 @@ -device.internal = 1 - -touch.deviceType = touchScreen -touch.orientationAware = 1 - -cursor.mode = navigation -cursor.orientationAware = 1 - -# This displayID matches the unique ID of the virtual display created for Emulator. -# This will indicate to input flinger than it should link this input device -# with the virtual display. -touch.displayId = local:3 diff --git a/input-mt/virtio_input_multi_touch_5.idc b/input-mt/virtio_input_multi_touch_5.idc deleted file mode 100644 index e489bb1f..00000000 --- a/input-mt/virtio_input_multi_touch_5.idc +++ /dev/null @@ -1,12 +0,0 @@ -device.internal = 1 - -touch.deviceType = touchScreen -touch.orientationAware = 1 - -cursor.mode = navigation -cursor.orientationAware = 1 - -# This displayID matches the unique ID of the virtual display created for Emulator. -# This will indicate to input flinger than it should link this input device -# with the virtual display. -touch.displayId = local:4 diff --git a/input/qwerty.kl b/input/qwerty.kl deleted file mode 100644 index f508dde4..00000000 --- a/input/qwerty.kl +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright (C) 2019 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# -# Emulator keyboard layout #1. -# -# This file is no longer used as the platform's default keyboard layout. -# Refer to Generic.kl instead. -# - -key 399 GRAVE -key 2 1 -key 3 2 -key 4 3 -key 5 4 -key 6 5 -key 7 6 -key 8 7 -key 9 8 -key 10 9 -key 11 0 -key 158 BACK -key 230 SOFT_RIGHT -key 60 SOFT_LEFT -key 107 ENDCALL -key 62 ENDCALL -key 229 MENU -key 139 MENU -key 59 MENU -key 127 SEARCH -key 217 SEARCH -key 228 POUND -key 227 STAR -key 231 CALL -key 61 CALL -key 232 DPAD_CENTER -key 108 DPAD_DOWN -key 103 DPAD_UP -key 102 HOME -key 105 DPAD_LEFT -key 106 DPAD_RIGHT -key 115 VOLUME_UP -key 114 VOLUME_DOWN -key 116 POWER -key 212 CAMERA - -key 16 Q -key 17 W -key 18 E -key 19 R -key 20 T -key 21 Y -key 22 U -key 23 I -key 24 O -key 25 P -key 26 LEFT_BRACKET -key 27 RIGHT_BRACKET -key 43 BACKSLASH - -key 30 A -key 31 S -key 32 D -key 33 F -key 34 G -key 35 H -key 36 J -key 37 K -key 38 L -key 39 SEMICOLON -key 40 APOSTROPHE -key 14 DEL - -key 44 Z -key 45 X -key 46 C -key 47 V -key 48 B -key 49 N -key 50 M -key 51 COMMA -key 52 PERIOD -key 53 SLASH -key 28 ENTER - -key 56 ALT_LEFT -key 100 ALT_RIGHT -key 42 SHIFT_LEFT -key 54 SHIFT_RIGHT -key 15 TAB -key 57 SPACE -key 150 EXPLORER -key 155 ENVELOPE -key 58 CAPS_LOCK - -key 12 MINUS -key 13 EQUALS -key 215 AT - -# On an AT keyboard: ESC, F10 -key 1 BACK -key 68 MENU - -# App switch = Overview key -key 580 APP_SWITCH - -# Media control keys -key 160 MEDIA_CLOSE -key 161 MEDIA_EJECT -key 163 MEDIA_NEXT -key 164 MEDIA_PLAY_PAUSE -key 165 MEDIA_PREVIOUS -key 166 MEDIA_STOP -key 167 MEDIA_RECORD -key 168 MEDIA_REWIND - -key 142 SLEEP -key 581 STEM_PRIMARY -key 582 STEM_1 -key 583 STEM_2 -key 584 STEM_3 diff --git a/input/virtio_input_multi_touch_1.idc b/input/virtio_input_multi_touch_1.idc index bc7ff663..78af5113 100644 --- a/input/virtio_input_multi_touch_1.idc +++ b/input/virtio_input_multi_touch_1.idc @@ -3,3 +3,4 @@ touch.deviceType = touchScreen touch.orientationAware = 1 cursor.mode = navigation cursor.orientationAware = 1 + diff --git a/kernel-tests/goldfish_kernel_tests_x86_64.mk b/kernel-tests/goldfish_kernel_tests_x86_64.mk index e3ccec62..19d4f0d6 100644 --- a/kernel-tests/goldfish_kernel_tests_x86_64.mk +++ b/kernel-tests/goldfish_kernel_tests_x86_64.mk @@ -29,8 +29,8 @@ THIS_DIR := device/generic/goldfish/kernel-tests # android.hardware. PRODUCT_PACKAGES += \ - android.hardware.keymaster@4.0-service \ - android.hardware.keymaster@4.0-impl \ + android.hardware.keymaster@3.0-service \ + android.hardware.keymaster@3.0-impl \ android.hardware.drm@1.1-service.clearkey \ android.hardware.graphics.allocator@2.0-service \ android.hardware.graphics.allocator@2.0-impl \ diff --git a/kernel-tests/manifest.xml b/kernel-tests/manifest.xml index 82ba6d19..a9173447 100644 --- a/kernel-tests/manifest.xml +++ b/kernel-tests/manifest.xml @@ -2,7 +2,7 @@ <hal format="hidl"> <name>android.hardware.keymaster</name> <transport>hwbinder</transport> - <version>4.0</version> + <version>3.0</version> <interface> <name>IKeymasterDevice</name> <instance>default</instance> diff --git a/keymaster/strongbox/Android.bp b/keymaster/strongbox/Android.bp index e615ba7a..39f4dcae 100644 --- a/keymaster/strongbox/Android.bp +++ b/keymaster/strongbox/Android.bp @@ -28,6 +28,7 @@ cc_binary { "libcutils", "libhardware", "libhidlbase", + "libhidltransport", "libkeymaster4", "liblog", "libutils", diff --git a/manifest-arm.xml b/manifest-arm.xml new file mode 100644 index 00000000..2189d914 --- /dev/null +++ b/manifest-arm.xml @@ -0,0 +1,215 @@ +<manifest version="1.0" type="device" target-level="3"> + <hal format="hidl"> + <name>android.hardware.drm</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>ICryptoFactory</name> + <instance>default</instance> + </interface> + <interface> + <name>IDrmFactory</name> + <instance>default</instance> + </interface> + <fqname>@1.1::ICryptoFactory/clearkey</fqname> + <fqname>@1.1::IDrmFactory/clearkey</fqname> + <fqname>@1.1::ICryptoFactory/widevine</fqname> + <fqname>@1.1::IDrmFactory/widevine</fqname> + </hal> + <hal format="hidl"> + <name>android.hardware.audio.effect</name> + <transport>hwbinder</transport> + <version>4.0</version> + <interface> + <name>IEffectsFactory</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.biometrics.fingerprint</name> + <transport>hwbinder</transport> + <version>2.1</version> + <interface> + <name>IBiometricsFingerprint</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.configstore</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>ISurfaceFlingerConfigs</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.audio</name> + <transport>hwbinder</transport> + <version>4.0</version> + <interface> + <name>IDevicesFactory</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.keymaster</name> + <transport>hwbinder</transport> + <version>3.0</version> + <interface> + <name>IKeymasterDevice</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.graphics.allocator</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>IAllocator</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.graphics.mapper</name> + <transport arch="32+64">passthrough</transport> + <version>2.0</version> + <interface> + <name>IMapper</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.graphics.composer</name> + <transport>hwbinder</transport> + <version>2.1</version> + <interface> + <name>IComposer</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.power</name> + <transport>hwbinder</transport> + <version>1.1</version> + <interface> + <name>IPower</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.broadcastradio</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IBroadcastRadioFactory</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.camera.provider</name> + <transport>hwbinder</transport> + <version>2.4</version> + <interface> + <name>ICameraProvider</name> + <instance>legacy/0</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.sensors</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>ISensors</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.gatekeeper</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IGatekeeper</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.gnss</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IGnss</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.media.omx</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IOmx</name> + <instance>default</instance> + </interface> + <interface> + <name>IOmxStore</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.radio</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IRadio</name> + <instance>slot1</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.wifi</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IWifi</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.wifi.hostapd</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IHostapd</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.wifi.supplicant</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>ISupplicant</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.health</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>IHealth</name> + <instance>default</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.thermal</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>IThermal</name> + <instance>default</instance> + </interface> + </hal> + <sepolicy> + <version>27.0</version> + </sepolicy> +</manifest> diff --git a/manifest.camera.xml b/manifest.camera.xml deleted file mode 100644 index 908c05c1..00000000 --- a/manifest.camera.xml +++ /dev/null @@ -1,11 +0,0 @@ -<manifest version="1.0" type="device" target-level="3"> - <hal format="hidl"> - <name>android.hardware.camera.provider</name> - <transport>hwbinder</transport> - <version>2.4</version> - <interface> - <name>ICameraProvider</name> - <instance>legacy/0</instance> - </interface> - </hal> -</manifest> diff --git a/manifest.gnss.xml b/manifest.gnss.xml deleted file mode 100644 index 69a178fd..00000000 --- a/manifest.gnss.xml +++ /dev/null @@ -1,11 +0,0 @@ -<manifest version="1.0" type="device" target-level="3"> - <hal format="hidl"> - <name>android.hardware.gnss</name> - <transport>hwbinder</transport> - <version>1.0</version> - <interface> - <name>IGnss</name> - <instance>default</instance> - </interface> - </hal> -</manifest> diff --git a/manifest.sensors.xml b/manifest.sensors.xml deleted file mode 100644 index 1c0a50b9..00000000 --- a/manifest.sensors.xml +++ /dev/null @@ -1,11 +0,0 @@ -<manifest version="1.0" type="device" target-level="3"> - <hal format="hidl"> - <name>android.hardware.sensors</name> - <transport>hwbinder</transport> - <version>1.0</version> - <interface> - <name>ISensors</name> - <instance>default</instance> - </interface> - </hal> -</manifest> diff --git a/manifest.xml b/manifest.xml index 53f344df..dd598e8a 100644 --- a/manifest.xml +++ b/manifest.xml @@ -37,7 +37,7 @@ <hal format="hidl"> <name>android.hardware.configstore</name> <transport>hwbinder</transport> - <version>1.1</version> + <version>1.0</version> <interface> <name>ISurfaceFlingerConfigs</name> <instance>default</instance> @@ -55,7 +55,7 @@ <hal format="hidl"> <name>android.hardware.keymaster</name> <transport>hwbinder</transport> - <version>4.0</version> + <version>3.0</version> <interface> <name>IKeymasterDevice</name> <instance>default</instance> @@ -82,7 +82,7 @@ <hal format="hidl"> <name>android.hardware.graphics.composer</name> <transport>hwbinder</transport> - <version>2.3</version> + <version>2.1</version> <interface> <name>IComposer</name> <instance>default</instance> @@ -100,47 +100,74 @@ <hal format="hidl"> <name>android.hardware.broadcastradio</name> <transport>hwbinder</transport> - <version>1.1</version> + <version>1.0</version> <interface> <name>IBroadcastRadioFactory</name> <instance>default</instance> </interface> </hal> <hal format="hidl"> - <name>android.hardware.media.omx</name> + <name>android.hardware.camera.provider</name> + <transport>hwbinder</transport> + <version>2.4</version> + <interface> + <name>ICameraProvider</name> + <instance>legacy/0</instance> + </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.sensors</name> <transport>hwbinder</transport> <version>1.0</version> <interface> - <name>IOmx</name> + <name>ISensors</name> <instance>default</instance> </interface> + </hal> + <hal format="hidl"> + <name>android.hardware.gatekeeper</name> + <transport>hwbinder</transport> + <version>1.0</version> <interface> - <name>IOmxStore</name> + <name>IGatekeeper</name> <instance>default</instance> </interface> </hal> <hal format="hidl"> - <name>android.hardware.radio</name> + <name>android.hardware.gnss</name> <transport>hwbinder</transport> - <version>1.1</version> + <version>1.0</version> <interface> - <name>IRadio</name> - <instance>slot1</instance> + <name>IGnss</name> + <instance>default</instance> </interface> </hal> <hal format="hidl"> - <name>android.hardware.soundtrigger</name> + <name>android.hardware.media.omx</name> <transport>hwbinder</transport> - <version>2.0</version> + <version>1.0</version> <interface> - <name>ISoundTriggerHw</name> + <name>IOmx</name> + <instance>default</instance> + </interface> + <interface> + <name>IOmxStore</name> <instance>default</instance> </interface> </hal> <hal format="hidl"> + <name>android.hardware.radio</name> + <transport>hwbinder</transport> + <version>1.0</version> + <interface> + <name>IRadio</name> + <instance>slot1</instance> + </interface> + </hal> + <hal format="hidl"> <name>android.hardware.wifi</name> <transport>hwbinder</transport> - <version>1.3</version> + <version>1.0</version> <interface> <name>IWifi</name> <instance>default</instance> @@ -158,7 +185,7 @@ <hal format="hidl"> <name>android.hardware.wifi.supplicant</name> <transport>hwbinder</transport> - <version>1.2</version> + <version>1.0</version> <interface> <name>ISupplicant</name> <instance>default</instance> @@ -173,4 +200,16 @@ <instance>default</instance> </interface> </hal> + <hal format="hidl"> + <name>android.hardware.thermal</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>IThermal</name> + <instance>default</instance> + </interface> + </hal> + <sepolicy> + <version>27.0</version> + </sepolicy> </manifest> diff --git a/network/netmgr/Android.bp b/network/netmgr/Android.bp index 7530c916..6686f989 100644 --- a/network/netmgr/Android.bp +++ b/network/netmgr/Android.bp @@ -22,15 +22,14 @@ cc_binary { "-Werror", ], srcs: [ - "bridge.cpp", - "bridge_builder.cpp", + "address_assigner.cpp", "commander.cpp", + "fork.cpp", "interface_state.cpp", "log.cpp", "main.cpp", "monitor.cpp", "poller.cpp", - "utils.cpp", "wifi_forwarder.cpp", "commands/wifi_command.cpp", ], diff --git a/network/netmgr/address_assigner.cpp b/network/netmgr/address_assigner.cpp new file mode 100644 index 00000000..11df81d8 --- /dev/null +++ b/network/netmgr/address_assigner.cpp @@ -0,0 +1,151 @@ +/* + * Copyright 2018, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "address_assigner.h" + +#include "log.h" + +#include <errno.h> +#include <net/if.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +AddressAssigner::AddressAssigner(const char* interfacePrefix, + in_addr_t baseAddress, + uint32_t maskLength) : + mInterfacePrefix(interfacePrefix), + mPrefixLength(strlen(interfacePrefix)), + mBaseAddress(baseAddress), + mMaskLength(maskLength) { + +} + +void AddressAssigner::onInterfaceState(unsigned int /*index*/, + const char* name, + InterfaceState state) { + if (strncmp(name, mInterfacePrefix, mPrefixLength) != 0) { + // The interface does not match the prefix, ignore this change + return; + } + + switch (state) { + case InterfaceState::Up: + assignAddress(name); + break; + case InterfaceState::Down: + freeAddress(name); + break; + } +} + +void AddressAssigner::assignAddress(const char* interfaceName) { + if (mMaskLength > 30) { + // The mask length is too long, we can't assign enough IP addresses from + // this. A maximum of 30 bits is supported, leaving 4 remaining + // addresses, one is network, one is broadcast, one is gateway, one is + // client. + return; + } + // Each subnet will have an amount of bits available to it that equals + // 32-bits - <mask length>, so if mask length is 29 there will be 3 + // remaining bits for each subnet. Then the distance between each subnet + // is 2 to the power of this number, in our example 2^3 = 8 so to get to the + // next subnet we add 8 to the network address. + in_addr_t increment = 1 << (32 - mMaskLength); + + // Convert the address to host byte-order first so we can do math on it. + for (in_addr_t addr = ntohl(mBaseAddress); true; addr += increment) { + // Take the reference of this lookup, that way we can assign a name to + // it if needed. + auto& usedName = mUsedIpAddresses[addr]; + if (usedName.empty()) { + // This address is not in use, let's use it + usedName = interfaceName; + // Make sure we convert back to network byte-order when setting it. + setIpAddress(interfaceName, htonl(addr)); + break; + } + } +} + +void AddressAssigner::setIpAddress(const char* interfaceName, + in_addr_t address) { + int sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock == -1) { + LOGE("AddressAssigner unable to open IP socket: %s", strerror(errno)); + return; + } + if (!setAddress(sock, SIOCSIFADDR, interfaceName, address)) { + LOGE("AddressAssigner unable to set interface address: %s", + strerror(errno)); + ::close(sock); + return; + } + + // The netmask is the inverted maximum value of the lower bits. That is if + // the mask length is 29 then the the largest value of the 3 (32-29) lowest + // bits is 7 (2^3 - 1) (111 binary). Inverting this value gives the netmask + // because it excludes those three bits and sets every other bit. + in_addr_t netmask = htonl(~((1 << (32 - mMaskLength)) - 1)); + + if (!setAddress(sock, SIOCSIFNETMASK, interfaceName, netmask)) { + LOGE("AddressAssigner unable to set interface netmask: %s", + strerror(errno)); + ::close(sock); + return; + } + + // The broadcast address is just the assigned address with all bits outside + // of the netmask set to one. + in_addr_t broadcast = address | ~netmask; + + if (!setAddress(sock, SIOCSIFBRDADDR, interfaceName, broadcast)) { + LOGE("AddressAssigner unable to set interface broadcast: %s", + strerror(errno)); + ::close(sock); + return; + } + ::close(sock); +} + +bool AddressAssigner::setAddress(int sock, + int type, + const char* interfaceName, + in_addr_t address) { + struct ifreq request; + memset(&request, 0, sizeof(request)); + strlcpy(request.ifr_name, interfaceName, sizeof(request.ifr_name)); + auto addr = reinterpret_cast<struct sockaddr_in*>(&request.ifr_addr); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = address; + + if (::ioctl(sock, type, &request) != 0) { + return false; + } + return true; +} + +void AddressAssigner::freeAddress(const char* interfaceName) { + for (auto& ipName : mUsedIpAddresses) { + if (ipName.second == interfaceName) { + // This is the one, free it up for future use + mUsedIpAddresses.erase(ipName.first); + } + } +} + diff --git a/network/netmgr/bridge_builder.h b/network/netmgr/address_assigner.h index e3d95805..dde42ee1 100644 --- a/network/netmgr/bridge_builder.h +++ b/network/netmgr/address_assigner.h @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Android Open Source Project + * Copyright 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,22 +18,37 @@ #include "interface_state.h" -#include <stddef.h> +#include <string> +#include <unordered_map> -class Bridge; +#include <netinet/in.h> +#include <stdint.h> -class BridgeBuilder { +class AddressAssigner { public: - // Construct a bridge builder that will add any interface that comes up to - // |bridge| if the interface name begins with |interfacePrefix|. - BridgeBuilder(Bridge& bridge, const char* interfacePrefix); + AddressAssigner(const char* interfacePrefix, + in_addr_t baseAddress, + uint32_t maskLength); void onInterfaceState(unsigned int index, const char* name, InterfaceState state); private: - Bridge& mBridge; + void assignAddress(const char* interfaceName); + void freeAddress(const char* interfaceName); + + void setIpAddress(const char* interfaceName, in_addr_t address); + bool setAddress(int socket, + int type, + const char* interfaceName, + in_addr_t address); + void removeIpAddress(const char* interfaceName, in_addr_t address); + const char* mInterfacePrefix; size_t mPrefixLength; + in_addr_t mBaseAddress; + uint32_t mMaskLength; + std::unordered_map<in_addr_t, std::string> mUsedIpAddresses; }; + diff --git a/network/netmgr/bridge.cpp b/network/netmgr/bridge.cpp deleted file mode 100644 index adbe21e6..00000000 --- a/network/netmgr/bridge.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "bridge.h" - -#include "log.h" - -#include <errno.h> -#include <net/if.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -Bridge::Bridge(const std::string& bridgeName) : mBridgeName(bridgeName) { -} - -Bridge::~Bridge() { - if (mSocketFd != -1) { - ::close(mSocketFd); - mSocketFd = -1; - } -} - -Result Bridge::init() { - Result res = createSocket(); - if (!res) { - return res; - } - res = createBridge(); - if (!res) { - return res; - } - return Result::success(); -} - -Result Bridge::addInterface(const std::string& interfaceName) { - return doInterfaceOperation(interfaceName, SIOCBRADDIF, "add"); -} - -Result Bridge::removeInterface(const std::string& interfaceName) { - return doInterfaceOperation(interfaceName, SIOCBRDELIF, "remove"); -} - -Result Bridge::createSocket() { - if (mSocketFd != -1) { - return Result::error("Bridge already initialized"); - } - mSocketFd = ::socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (mSocketFd < 0) { - return Result::error("Unable to create socket for bridge: %s", - strerror(errno)); - } - return Result::success(); -} - -Result Bridge::createBridge() { - int res = ::ioctl(mSocketFd, SIOCBRADDBR, mBridgeName.c_str()); - if (res < 0) { - // If the bridge already exists we just keep going, that's fine. - // Otherwise something went wrong. - if (errno != EEXIST) { - return Result::error("Cannot create bridge %s: %s", - mBridgeName.c_str(), strerror(errno)); - } - } - - struct ifreq request; - memset(&request, 0, sizeof(request)); - // Determine interface index of bridge - request.ifr_ifindex = if_nametoindex(mBridgeName.c_str()); - if (request.ifr_ifindex == 0) { - return Result::error("Unable to get bridge %s interface index", - mBridgeName.c_str()); - } - // Get bridge interface flags - strlcpy(request.ifr_name, mBridgeName.c_str(), sizeof(request.ifr_name)); - res = ::ioctl(mSocketFd, SIOCGIFFLAGS, &request); - if (res != 0) { - return Result::error("Unable to get interface flags for bridge %s: %s", - mBridgeName.c_str(), strerror(errno)); - } - - if ((request.ifr_flags & IFF_UP) != 0) { - // Bridge is already up, it's ready to go - return Result::success(); - } - - // Bridge is not up, it needs to be up to work - request.ifr_flags |= IFF_UP; - res = ::ioctl(mSocketFd, SIOCSIFFLAGS, &request); - if (res != 0) { - return Result::error("Unable to set interface flags for bridge %s: %s", - strerror(errno)); - } - - return Result::success(); -} - -Result Bridge::doInterfaceOperation(const std::string& interfaceName, - unsigned long operation, - const char* operationName) { - struct ifreq request; - memset(&request, 0, sizeof(request)); - - request.ifr_ifindex = if_nametoindex(interfaceName.c_str()); - if (request.ifr_ifindex == 0) { - return Result::error("Bridge unable to %s interface '%s', no such " - "interface", operationName, interfaceName.c_str()); - } - strlcpy(request.ifr_name, mBridgeName.c_str(), sizeof(request.ifr_name)); - int res = ::ioctl(mSocketFd, operation, &request); - // An errno of EBUSY most likely indicates that the interface is already - // part of the bridge. Ignore this. - if (res < 0 && errno != EBUSY) { - return Result::error("Bridge unable to %s interface '%s': %s", - operationName, interfaceName.c_str(), - strerror(errno)); - } - return Result::success(); -} diff --git a/network/netmgr/bridge.h b/network/netmgr/bridge.h deleted file mode 100644 index fc7ff519..00000000 --- a/network/netmgr/bridge.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "result.h" - -#include <string> - -class Bridge { -public: - explicit Bridge(const std::string& bridgeName); - ~Bridge(); - - Result init(); - - Result addInterface(const std::string& interfaceName); - Result removeInterface(const std::string& interfaceName); -private: - Result createSocket(); - Result createBridge(); - Result doInterfaceOperation(const std::string& interfaceName, - unsigned long operation, - const char* operationName); - - std::string mBridgeName; - int mSocketFd = -1; -}; diff --git a/network/netmgr/bridge_builder.cpp b/network/netmgr/bridge_builder.cpp deleted file mode 100644 index d772eaef..00000000 --- a/network/netmgr/bridge_builder.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "bridge_builder.h" - -#include "bridge.h" -#include "log.h" -#include "result.h" - -BridgeBuilder::BridgeBuilder(Bridge& bridge, const char* interfacePrefix) : - mBridge(bridge), - mInterfacePrefix(interfacePrefix), - mPrefixLength(strlen(interfacePrefix)) { -} - -void BridgeBuilder::onInterfaceState(unsigned int /*index*/, - const char* name, - InterfaceState state) { - if (strncmp(name, mInterfacePrefix, mPrefixLength) != 0) { - // Does not match our prefix, ignore it - return; - } - - if (state == InterfaceState::Up) { - Result res = mBridge.addInterface(name); - if (!res) { - LOGE("%s", res.c_str()); - } - } -} diff --git a/network/netmgr/commands/wifi_command.cpp b/network/netmgr/commands/wifi_command.cpp index 27bf95a8..8f48a438 100644 --- a/network/netmgr/commands/wifi_command.cpp +++ b/network/netmgr/commands/wifi_command.cpp @@ -16,13 +16,18 @@ #include "wifi_command.h" -#include "../bridge.h" -#include "../utils.h" +#include "../fork.h" +#include "log.h" #include <cutils/properties.h> #include <errno.h> +#include <net/if.h> +#include <netinet/in.h> #include <stdio.h> #include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/types.h> #include <unistd.h> static const char kHostApdStubFile[] = "/vendor/etc/simulated_hostapd.conf"; @@ -65,9 +70,24 @@ private: int mFd; }; -WifiCommand::WifiCommand(Bridge& bridge) - : mBridge(bridge) - , mLowestInterfaceNumber(1) { +std::vector<std::string> explode(const char* str) { + const char* cur = str; + const char* space = nullptr; + std::vector<std::string> result; + do { + space = ::strchr(cur, ' '); + if (space) { + result.emplace_back(cur, space); + cur = space + 1; + } else { + result.emplace_back(cur); + } + } while (space); + + return result; +} + +WifiCommand::WifiCommand() : mLowestInterfaceNumber(1) { readConfig(); } @@ -83,7 +103,7 @@ Result WifiCommand::onCommand(const char* /*command*/, const char* args) { return Result::error("Empty wifi command"); } - std::vector<std::string> subArgs = explode(divider + 1, ' '); + std::vector<std::string> subArgs = explode(divider + 1); if (subArgs.empty()) { // All of these commands require sub arguments return Result::error("Missing argument to command '%s'", @@ -152,6 +172,55 @@ Result WifiCommand::triggerHostApd() { return Result::success(); } +static const char* sSetForwardRule[] = {"/system/bin/iptables", + "-w", // Wait for iptables lock if + "-W", // needed. This prevents + "50000", // spurious failures. + "<AddOrDelete>", // To be replaced + "FORWARD", + "-i", + "<InInterface>", // To be replaced + "-o", + "<OutInterface>", // To be replaced + "-j", + "DROP", + nullptr }; + +static const char kIpTables[] = "/system/bin/iptables"; +static const char kIp6Tables[] = "/system/bin/ip6tables"; +static const char kAddRule[] = "-A"; +static const char kDeleteRule[] = "-D"; +static const size_t kIpTablesIndex = 0; +static const size_t kActionIndex = 4; +static const size_t kInInterfaceIndex = 7; +static const size_t kOutInterfaceIndex = 9; + + +Result WifiCommand::setBlocked(const char* ifName, bool blocked) { + // Blocking means adding block rules, unblocking means removing them + sSetForwardRule[kActionIndex] = blocked ? kAddRule : kDeleteRule; + + // Do this for both IPv4 and IPv6 to ensure all traffic is blocked/unblocked + for (const auto& iptables : { kIpTables, kIp6Tables }) { + // Block traffic coming in from the outside world to this wlan + sSetForwardRule[kIpTablesIndex] = iptables; + sSetForwardRule[kInInterfaceIndex] = "eth0"; + sSetForwardRule[kOutInterfaceIndex] = ifName; + if (!forkAndExec(sSetForwardRule)) { + return Result::error("Internal error: Unable to %s network", + blocked ? "block" : "unblock"); + } + // Block traffic going from the wlan to the outside world + sSetForwardRule[kInInterfaceIndex] = ifName; + sSetForwardRule[kOutInterfaceIndex] = "eth0"; + if (!forkAndExec(sSetForwardRule)) { + return Result::error("Internal error: Unable to %s network", + blocked ? "block" : "unblock"); + } + } + return Result::success(); +} + Result WifiCommand::onAdd(const std::vector<std::string>& arguments) { AccessPoint& ap = mAccessPoints[arguments[0]]; ap.ssid = arguments[0]; @@ -187,18 +256,18 @@ Result WifiCommand::onAdd(const std::vector<std::string>& arguments) { Result WifiCommand::onBlock(const std::vector<std::string>& arguments) { auto interface = mAccessPoints.find(arguments[0]); if (interface == mAccessPoints.end()) { - return Result::error("Unknown SSID '%s'", arguments[0].c_str()); + return Result::error("Unknown SSID '%s", arguments[0].c_str()); } interface->second.blocked = true; - return mBridge.removeInterface(interface->second.ifName.c_str()); + return setBlocked(interface->second.ifName.c_str(), true); } Result WifiCommand::onUnblock(const std::vector<std::string>& arguments) { auto interface = mAccessPoints.find(arguments[0]); if (interface == mAccessPoints.end()) { - return Result::error("Unknown SSID '%s'", arguments[0].c_str()); + return Result::error("Unknown SSID '%s", arguments[0].c_str()); } interface->second.blocked = false; - return mBridge.addInterface(interface->second.ifName.c_str()); + return setBlocked(interface->second.ifName.c_str(), false); } diff --git a/network/netmgr/commands/wifi_command.h b/network/netmgr/commands/wifi_command.h index b47edb89..f9ce96ce 100644 --- a/network/netmgr/commands/wifi_command.h +++ b/network/netmgr/commands/wifi_command.h @@ -24,11 +24,9 @@ #include <unordered_set> #include <vector> -class Bridge; - class WifiCommand : public Command { public: - explicit WifiCommand(Bridge& bridge); + WifiCommand(); virtual ~WifiCommand() = default; Result onCommand(const char* command, const char* args) override; @@ -36,6 +34,7 @@ private: void readConfig(); Result writeConfig(); Result triggerHostApd(); + Result setBlocked(const char* ifName, bool blocked); Result onAdd(const std::vector<std::string>& args); Result onBlock(const std::vector<std::string>& args); @@ -49,7 +48,6 @@ private: bool blocked; }; - Bridge& mBridge; std::unordered_map<std::string, AccessPoint> mAccessPoints; std::unordered_set<std::string> mUsedInterfaces; int mLowestInterfaceNumber; diff --git a/network/netmgr/interface_state.h b/network/netmgr/interface_state.h index 6d56aba1..5315b0f9 100644 --- a/network/netmgr/interface_state.h +++ b/network/netmgr/interface_state.h @@ -21,4 +21,3 @@ enum class InterfaceState { Down, }; -const char* interfaceStateToStr(InterfaceState state); diff --git a/network/netmgr/main.cpp b/network/netmgr/main.cpp index d83de399..e4b43f6d 100644 --- a/network/netmgr/main.cpp +++ b/network/netmgr/main.cpp @@ -14,28 +14,23 @@ * limitations under the License. */ -#include "bridge.h" -#include "bridge_builder.h" +#include "address_assigner.h" #include "commander.h" #include "commands/wifi_command.h" #include "log.h" #include "monitor.h" #include "poller.h" -#include "utils.h" #include "wifi_forwarder.h" #include <arpa/inet.h> #include <netinet/in.h> -#include <cutils/properties.h> - #include <functional> -static const char kBridgeName[] = "br0"; -static const char kNetworkBridgedProperty[] = "vendor.network.bridged"; +static const char kWifiMonitorInterface[] = "hwsim0"; static void usage(const char* name) { - LOGE("Usage: %s --if-prefix <prefix> --bridge <if1,if2,...>", name); + LOGE("Usage: %s --if-prefix <prefix> --network <ip/mask>", name); LOGE(" <prefix> indicates the name of network interfaces to configure."); LOGE(" <ip/mask> is the base IP address to assign to the first interface"); LOGE(" and mask indicates the netmask and broadcast to set."); @@ -44,27 +39,52 @@ static void usage(const char* name) { LOGE(" and the size of the subnet is indicated by <mask>"); } -static Result addBridgeInterfaces(Bridge& bridge, const char* interfaces) { - std::vector<std::string> ifNames = explode(interfaces, ','); +static bool parseNetwork(const char* network, + in_addr_t* address, + uint32_t* mask) { + const char* divider = strchr(network, '/'); + if (divider == nullptr) { + LOGE("Network specifier '%s' is missing netmask length", network); + return false; + } + if (divider - network >= INET_ADDRSTRLEN) { + LOGE("Network specifier '%s' contains an IP address that is too long", + network); + return false; + } - for (const auto& ifName : ifNames) { - Result res = bridge.addInterface(ifName); - if (!res) { - return res; - } + char buffer[INET_ADDRSTRLEN]; + strlcpy(buffer, network, divider - network + 1); + struct in_addr addr; + if (!::inet_aton(buffer, &addr)) { + // String could not be converted to IP address + LOGE("Network specifier '%s' contains an invalid IP address '%s'", + network, buffer); + return false; } - return Result::success(); + + ++divider; + + char dummy = 0; + if (sscanf(divider, "%u%c", mask, &dummy) != 1) { + LOGE("Netork specifier '%s' contains an invalid netmask length '%s'", + network, divider); + return false; + } + + *address = addr.s_addr; + return true; } int main(int argc, char* argv[]) { const char* interfacePrefix = nullptr; - const char* bridgeInterfaces = nullptr; + const char* network = nullptr; for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "--if-prefix") == 0 && i + 1 < argc) { interfacePrefix = argv[++i]; - } else if (strcmp(argv[i], "--bridge") == 0 && i + 1 < argc) { - bridgeInterfaces = argv[++i]; + } else if (strcmp(argv[i], "--network") == 0 && i + 1 < argc) { + network = argv[++i]; } else { LOGE("Unknown parameter '%s'", argv[i]); usage(argv[0]); @@ -75,39 +95,30 @@ int main(int argc, char* argv[]) { if (interfacePrefix == nullptr) { LOGE("Missing parameter --if-prefix"); } - if (bridgeInterfaces == nullptr) { - LOGE("Missing parameter --bridge"); + if (network == nullptr) { + LOGE("Missing parameter --network"); } - if (interfacePrefix == nullptr || bridgeInterfaces == nullptr) { + if (network == nullptr || interfacePrefix == nullptr) { usage(argv[0]); return 1; } - Bridge bridge(kBridgeName); - Result res = bridge.init(); - if (!res) { - LOGE("%s", res.c_str()); - return 1; - } - res = addBridgeInterfaces(bridge, bridgeInterfaces); - if (!res) { - LOGE("%s", res.c_str()); + in_addr_t address = 0; + uint32_t mask = 0; + if (!parseNetwork(network, &address, &mask)) { return 1; } - BridgeBuilder bridgeBuilder(bridge, interfacePrefix); - - property_set(kNetworkBridgedProperty, "1"); - + AddressAssigner assigner(interfacePrefix, address, mask); Monitor monitor; - monitor.setOnInterfaceState(std::bind(&BridgeBuilder::onInterfaceState, - &bridgeBuilder, + monitor.setOnInterfaceState(std::bind(&AddressAssigner::onInterfaceState, + &assigner, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - res = monitor.init(); + Result res = monitor.init(); if (!res) { LOGE("%s", res.c_str()); return 1; @@ -120,13 +131,20 @@ int main(int argc, char* argv[]) { return 1; } - WifiCommand wifiCommand(bridge); + WifiCommand wifiCommand; commander.registerCommand("wifi", &wifiCommand); + WifiForwarder forwarder(kWifiMonitorInterface); + res = forwarder.init(); + if (!res) { + LOGE("%s", res.c_str()); + return 1; + } + Poller poller; poller.addPollable(&monitor); poller.addPollable(&commander); - + poller.addPollable(&forwarder); return poller.run(); } diff --git a/network/netmgr/monitor.cpp b/network/netmgr/monitor.cpp index a9d248ae..4ab111ea 100644 --- a/network/netmgr/monitor.cpp +++ b/network/netmgr/monitor.cpp @@ -37,11 +37,7 @@ Monitor::~Monitor() { } Result Monitor::init() { - Result res = openSocket(); - if (!res) { - return res; - } - return requestInterfaces(); + return openSocket(); } void Monitor::setOnInterfaceState(OnInterfaceStateCallback callback) { @@ -88,7 +84,7 @@ bool Monitor::onReadAvailable(int /*fd*/, int* /*status*/) { default: break; } - hdr = NLMSG_NEXT(hdr, length); + NLMSG_NEXT(hdr, length); } } } @@ -144,36 +140,6 @@ Result Monitor::openSocket() { return Result::success(); } -Result Monitor::requestInterfaces() { - if (mSocketFd == -1) { - return Result::error("Monitor not initialized yet"); - } - - struct { - struct nlmsghdr hdr; - struct rtgenmsg gen; - } request; - - memset(&request, 0, sizeof(request)); - - request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.gen)); - request.hdr.nlmsg_type = RTM_GETLINK; - request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - request.hdr.nlmsg_seq = 1; - request.hdr.nlmsg_pid = getpid(); - request.gen.rtgen_family = AF_PACKET; - - ssize_t result = TEMP_FAILURE_RETRY(::send(mSocketFd, - &request, - request.hdr.nlmsg_len, - 0)); - if (result < 0) { - return Result::error("Failed to request interfaces: %s", - strerror(errno)); - } - return Result::success(); -} - void Monitor::closeSocket() { if (mSocketFd != -1) { ::close(mSocketFd); @@ -188,23 +154,14 @@ void Monitor::handleNewLink(const struct nlmsghdr* hdr) { auto msg = reinterpret_cast<const struct ifinfomsg*>(NLMSG_DATA(hdr)); - char name[IF_NAMESIZE + 1] = { 0 }; - const unsigned int ifIndex = msg->ifi_index; - if (if_indextoname(ifIndex, name) == nullptr) { - LOGE("Unable to get interface name for interface index %u", ifIndex); - } + if (msg->ifi_change & IFF_UP) { + // The interface up/down flag changed, send a notification + char name[IF_NAMESIZE + 1] = { 0 }; + if_indextoname(msg->ifi_index, name); - bool isUp = !!(msg->ifi_flags & IFF_UP); - auto iterator = mUpInterfaces.find(ifIndex); - - if (iterator == mUpInterfaces.end() && isUp) { - // The interface was not known to be up but is up, known state changed - mUpInterfaces.insert(ifIndex); - mOnInterfaceStateCallback(ifIndex, name, InterfaceState::Up); - } else if (iterator != mUpInterfaces.end() && !isUp) { - // The interface was known to be up, now it's not, known state changed - mUpInterfaces.erase(iterator); - mOnInterfaceStateCallback(ifIndex, name, InterfaceState::Down); + InterfaceState state = (msg->ifi_flags & IFF_UP) ? InterfaceState::Up : + InterfaceState::Down; + mOnInterfaceStateCallback(msg->ifi_index, name, state); } } diff --git a/network/netmgr/monitor.h b/network/netmgr/monitor.h index 00f525ee..3d2dc621 100644 --- a/network/netmgr/monitor.h +++ b/network/netmgr/monitor.h @@ -20,7 +20,7 @@ #include "pollable.h" #include "result.h" -#include <unordered_set> +const char* interfaceStateToStr(InterfaceState state); /** Monitor network interfaces and provide notifications of changes to those * interfaces. @@ -46,12 +46,10 @@ public: private: Result openSocket(); - Result requestInterfaces(); void closeSocket(); void handleNewLink(const struct nlmsghdr* hdr); int mSocketFd; OnInterfaceStateCallback mOnInterfaceStateCallback; - std::unordered_set<unsigned int> mUpInterfaces; }; diff --git a/network/netmgr/utils.h b/network/netmgr/timestamp.cpp index 7c05882c..36c79ee0 100644 --- a/network/netmgr/utils.h +++ b/network/netmgr/timestamp.cpp @@ -14,9 +14,20 @@ * limitations under the License. */ -#pragma once +#include "timestamp.h" -#include <string> -#include <vector> -std::vector<std::string> explode(const char* str, char divider); +Timestamp::Timestamp() { + memset(&mTime, 0, sizeof(mTime)); +} + +static Timestamp Timestamp::now() { + Timestamp t; + clock_gettime(CLOCK_MONOTONIC, &t.mTime); + return t; +} + +bool Timestamp::operator==(const Timestamp& other) const { +} +bool Timestamp::operator<(const Timestamp& other) const { +} diff --git a/network/wifi_forwarder/poller.h b/network/netmgr/timestamp.h index 9794f4da..8ad7bf81 100644 --- a/network/wifi_forwarder/poller.h +++ b/network/netmgr/timestamp.h @@ -16,19 +16,18 @@ #pragma once -#include <vector> +#include <time.h> -#include "pollable.h" - -class Poller { +class Timestamp { public: - Poller(); + Timestamp(); - void addPollable(Pollable* pollable); + static Timestamp now(); - int run(); + bool operator==(const Timestamp& other) const; + bool operator<(const Timestamp& other) const; private: - std::vector<Pollable*> mPollables; + struct timespec mTime; }; diff --git a/network/netmgr/utils.cpp b/network/netmgr/utils.cpp deleted file mode 100644 index fa71c1e1..00000000 --- a/network/netmgr/utils.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils.h" - -#include <string.h> - -std::vector<std::string> explode(const char* str, char divider) { - const char* cur = str; - const char* space = nullptr; - std::vector<std::string> result; - do { - space = ::strchr(cur, divider); - if (space) { - result.emplace_back(cur, space); - cur = space + 1; - } else { - result.emplace_back(cur); - } - } while (space); - - return result; -} - diff --git a/network/wifi_forwarder/Android.bp b/network/wifi_forwarder/Android.bp deleted file mode 100644 index 6dbc9ca1..00000000 --- a/network/wifi_forwarder/Android.bp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -cc_binary { - name: "wifi_forwarder", - vendor: true, - cppflags: [ - "-Wall", - "-Werror", - "--std=c++17", - ], - srcs: [ - "frame.cpp", - "local_connection.cpp", - "main.cpp", - "netlink_message.cpp", - "netlink_socket.cpp", - "poller.cpp", - "remote_connection.cpp", - "wifi_forwarder.cpp", - ], - shared_libs: [ - "libcutils", - "liblog", - "libnl", - "libpcap", - "libutils", - "libutilscallstack", - ], - header_libs: [ - "goldfish_headers", - ], -} diff --git a/network/wifi_forwarder/cache.h b/network/wifi_forwarder/cache.h deleted file mode 100644 index bd64f1a4..00000000 --- a/network/wifi_forwarder/cache.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <inttypes.h> -#include "log.h" - -#include <chrono> -#include <unordered_map> - -// Default amount of time until a cache entry expires -static constexpr auto kDefaultCacheTimeout = std::chrono::seconds(30); - -template<typename Key, - typename Value, - typename Timestamp = std::chrono::steady_clock::time_point> -class Cache { -public: - using TimedValue = std::pair<Timestamp, Value>; - - using MapType = std::unordered_map<Key, TimedValue>; - using key_type = typename MapType::key_type; - using mapped_type = Value; - - class ConstIterator { - public: - class IterPair { - public: - IterPair(const Key& key, const Value& value) - : first(key), second(value) { - } - - const IterPair* operator->() const { return this; } - const Key& first; - const Value& second; - private: - }; - - ConstIterator(typename MapType::const_iterator current) - : mCurrent(current) { } - - IterPair operator->() const { - return IterPair(mCurrent->first, mCurrent->second.second); - } - - IterPair operator*() const { - return IterPair(mCurrent->first, mCurrent->second.second); - } - - bool operator==(const ConstIterator& other) const { - return mCurrent == other.mCurrent; - } - - bool operator!=(const ConstIterator& other) const { - return mCurrent != other.mCurrent; - } - - typename MapType::const_iterator internal() const { return mCurrent; } - - private: - typename MapType::const_iterator mCurrent; - }; - class Iterator { - public: - class IterPair { - public: - IterPair(const Key& key, Value& value) : first(key), second(value) { } - - IterPair* operator->() { return this; } - const Key& first; - Value& second; - private: - }; - - Iterator(typename MapType::iterator current) : mCurrent(current) { } - - IterPair operator->() { - return IterPair(mCurrent->first, mCurrent->second.second); - } - - IterPair operator*() { - return IterPair(mCurrent->first, mCurrent->second.second); - } - - bool operator==(const Iterator& other) const { - return mCurrent == other.mCurrent; - } - - bool operator!=(const Iterator& other) const { - return mCurrent != other.mCurrent; - } - - typename MapType::iterator internal() { return mCurrent; } - - private: - typename MapType::iterator mCurrent; - }; - - using iterator = Iterator; - using const_iterator = ConstIterator; - using insert_return_type = std::pair<const_iterator, bool>; - - Cache(std::chrono::milliseconds timeout = kDefaultCacheTimeout) - : mTimeout(timeout) { - } - - template<typename M> - insert_return_type insert_or_assign(const key_type& key, M&& value) { - std::pair<typename MapType::iterator,bool> inserted = - mMap.insert_or_assign(key, TimedValue(mCurrentTime, - std::move(value))); - return insert_return_type(inserted.first, inserted.second); - } - - mapped_type& operator[](const key_type& key) { - TimedValue& v = mMap[key]; - v.first = mCurrentTime; - return v.second; - } - - iterator find(const key_type& key) { - return iterator(mMap.find(key)); - } - - const_iterator find(const key_type& key) const { - return const_iterator(mMap.find(key)); - } - - iterator erase(const_iterator pos) { - return iterator(mMap.erase(pos.internal())); - } - - iterator erase(iterator pos) { - return iterator(mMap.erase(pos.internal())); - } - - size_t erase(const key_type& key) { - return mMap.erase(key); - } - - iterator begin() { - return iterator(mMap.begin()); - } - - iterator end() { - return iterator(mMap.end()); - } - - const_iterator begin() const { - return const_iterator(mMap.begin()); - } - - const_iterator end() const { - return const_iterator(mMap.end()); - } - - void setCurrentTime(Timestamp currentTime) { - mCurrentTime = currentTime; - } - - void expireEntries() { - for (auto it = mMap.begin(); it != mMap.end(); ) { - const Timestamp timestamp = it->second.first; - if (mCurrentTime > timestamp && - (mCurrentTime - timestamp) > mTimeout) { - // This entry has expired, remove it - it = mMap.erase(it); - } else { - ++it; - } - } - } -private: - const std::chrono::milliseconds mTimeout; - Timestamp mCurrentTime; - MapType mMap; -}; - diff --git a/network/wifi_forwarder/frame.cpp b/network/wifi_forwarder/frame.cpp deleted file mode 100644 index 3b20b4e1..00000000 --- a/network/wifi_forwarder/frame.cpp +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "frame.h" - -#include "hwsim.h" -#include "ieee80211.h" - -#include <asm/byteorder.h> - -#include <sstream> - -static constexpr uint64_t kSlotTime = 9; - -static const AccessCategory kPriorityToAc[8] = { - AccessCategory::BestEffort, - AccessCategory::Background, - AccessCategory::Background, - AccessCategory::BestEffort, - AccessCategory::Video, - AccessCategory::Video, - AccessCategory::Voice, - AccessCategory::Voice, -}; - -static uint32_t calcContentionWindowMin(AccessCategory ac) { - switch (ac) { - case AccessCategory::Voice: - return 3; - case AccessCategory::Video: - return 7; - case AccessCategory::BestEffort: - return 15; - case AccessCategory::Background: - return 15; - } -} - -static uint32_t calcContentionWindowMax(AccessCategory ac) { - switch (ac) { - case AccessCategory::Voice: - return 7; - case AccessCategory::Video: - return 15; - case AccessCategory::BestEffort: - return 1023; - case AccessCategory::Background: - return 1023; - } -} - -FrameType frameTypeFromByte(uint8_t byte) { - if (byte == static_cast<uint8_t>(FrameType::Ack)) { - return FrameType::Ack; - } else if (byte == static_cast<uint8_t>(FrameType::Data)) { - return FrameType::Data; - } - return FrameType::Unknown; -} - -FrameInfo::FrameInfo(const MacAddress& transmitter, - uint64_t cookie, - uint32_t flags, - uint32_t channel, - const hwsim_tx_rate* rates, - size_t numRates) - : mTransmitter(transmitter) - , mCookie(cookie) - , mFlags(flags) - , mChannel(channel) { - size_t i = 0; - for (; i < numRates; ++i) { - mTxRates[i].count = 0; - mTxRates[i].idx = rates[i].idx; - } - for (; i < mTxRates.size(); ++i) { - mTxRates[i].count = 0; - mTxRates[i].idx = -1; - } -} - -bool FrameInfo::shouldAck() const { - return !!(mFlags & HWSIM_TX_CTL_REQ_TX_STATUS); -} - -Frame::Frame(const uint8_t* data, size_t size) : mData(data, data + size) { -} - -Frame::Frame(const uint8_t* data, size_t size, const MacAddress& transmitter, - uint64_t cookie, uint32_t flags, uint32_t channel, - const hwsim_tx_rate* rates, size_t numRates) - : mData(data, data + size) - , mInfo(transmitter, cookie, flags, channel, rates, numRates) - , mContentionWindow(calcContentionWindowMin(getAc())) - , mContentionWindowMax(calcContentionWindowMax(getAc())) { - memcpy(mInitialTxRates.data(), rates, numRates * sizeof(*rates)); -} - -bool Frame::incrementAttempts() { - Rates& rates = mInfo.rates(); - for (size_t i = 0; i < rates.size(); ++i) { - if (mInitialTxRates[i].idx == -1) { - // We've run out of attempts - break; - } - if (rates[i].count < mInitialTxRates[i].count) { - ++rates[i].count; - return true; - } - } - return false; -} - -bool Frame::hasRemainingAttempts() { - Rates& rates = mInfo.rates(); - for (size_t i = 0; i < rates.size(); ++i) { - if (mInitialTxRates[i].idx == -1) { - break; - } - if (rates[i].count < mInitialTxRates[i].count) { - return true; - } - } - return false; -} - -const MacAddress& Frame::source() const { - auto hdr = reinterpret_cast<const struct ieee80211_hdr*>(mData.data()); - return *reinterpret_cast<const MacAddress*>(hdr->addr2); -} - -const MacAddress& Frame::destination() const { - auto hdr = reinterpret_cast<const struct ieee80211_hdr*>(mData.data()); - return *reinterpret_cast<const MacAddress*>(hdr->addr1); -} - -std::string Frame::str() const { - uint8_t type = (mData[0] >> 2) & 0x3; - uint8_t subType = (mData[0] >> 4) & 0x0F; - - std::stringstream ss; - ss << "[ Ck: " << cookie() << " Ch: " << channel() << " ] "; - switch (type) { - case 0: - // Management - ss << "Management ("; - switch (subType) { - case 0: - ss << "Association Request"; - break; - case 1: - ss << "Association Response"; - break; - case 2: - ss << "Reassociation Request"; - break; - case 3: - ss << "Reassociation Response"; - break; - case 4: - ss << "Probe Request"; - break; - case 5: - ss << "Probe Response"; - break; - case 6: - ss << "Timing Advertisement"; - break; - case 8: - ss << "Beacon"; - break; - case 9: - ss << "ATIM"; - break; - case 10: - ss << "Disassociation"; - break; - case 11: - ss << "Authentication"; - break; - case 12: - ss << "Deauthentication"; - break; - case 13: - ss << "Action"; - break; - case 14: - ss << "Action No Ack"; - break; - default: - ss << subType; - break; - } - ss << ')'; - break; - case 1: - // Control - ss << "Control ("; - switch (subType) { - case 4: - ss << "Beamforming Report Poll"; - break; - case 5: - ss << "VHT NDP Announcement"; - break; - case 6: - ss << "Control Frame Extension"; - break; - case 7: - ss << "Control Wrapper"; - break; - case 8: - ss << "Block Ack Request"; - break; - case 9: - ss << "Block Ack"; - break; - case 10: - ss << "PS-Poll"; - break; - case 11: - ss << "RTS"; - break; - case 12: - ss << "CTS"; - break; - case 13: - ss << "Ack"; - break; - case 14: - ss << "CF-End"; - break; - case 15: - ss << "CF-End+CF-Ack"; - break; - default: - ss << subType; - break; - } - ss << ')'; - break; - case 2: - // Data - ss << "Data ("; - switch (subType) { - case 0: - ss << "Data"; - break; - case 1: - ss << "Data+CF-Ack"; - break; - case 2: - ss << "Data+CF-Poll"; - break; - case 3: - ss << "Data+CF-Ack+CF-Poll"; - break; - case 4: - ss << "Null"; - break; - case 5: - ss << "CF-Ack"; - break; - case 6: - ss << "CF-Poll"; - break; - case 7: - ss << "CF-Ack+CF-Poll"; - break; - case 8: - ss << "QoS Data"; - break; - case 9: - ss << "QoS Data+CF-Ack"; - break; - case 10: - ss << "QoS Data+CF-Poll"; - break; - case 11: - ss << "QoS Data+CF-Ack+CF-Poll"; - break; - case 12: - ss << "QoS Null"; - break; - case 14: - ss << "QoS CF-Poll"; - break; - case 15: - ss << "QoS CF-Poll+CF-Ack"; - break; - default: - ss << subType; - break; - } - ss << ')'; - break; - case 3: - // Extension - ss << "Extension ("; - switch (subType) { - case 0: - ss << "DMG Beacon"; - break; - default: - ss << subType; - break; - } - ss << ')'; - break; - default: - ss << type << " (" << subType << ')'; - break; - } - return ss.str(); -} - -bool Frame::isBeacon() const { - uint8_t totalType = mData[0] & 0xFC; - return totalType == 0x80; -} - -bool Frame::isData() const { - uint8_t totalType = mData[0] & 0x0C; - return totalType == 0x08; -} - -bool Frame::isDataQoS() const { - uint8_t totalType = mData[0] & 0xFC; - return totalType == 0x88; -} - -uint16_t Frame::getQoSControl() const { - // Some frames have 4 address fields instead of 3 which pushes QoS control - // forward 6 bytes. - bool uses4Addresses = !!(mData[1] & 0x03); - const uint8_t* addr = &mData[uses4Addresses ? 30 : 24]; - - return __le16_to_cpu(*reinterpret_cast<const uint16_t*>(addr)); -} - -uint64_t Frame::calcNextTimeout() { - mNextTimeout = (mContentionWindow * kSlotTime) / 2; - mContentionWindow = std::min((mContentionWindow * 2) + 1, - mContentionWindowMax); - return mNextTimeout; -} - -AccessCategory Frame::getAc() const { - if (!isData()) { - return AccessCategory::Voice; - } - if (!isDataQoS()) { - return AccessCategory::BestEffort; - } - uint16_t priority = getQoSControl() & 0x07; - return kPriorityToAc[priority]; -} diff --git a/network/wifi_forwarder/frame.h b/network/wifi_forwarder/frame.h deleted file mode 100644 index ac76f827..00000000 --- a/network/wifi_forwarder/frame.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "macaddress.h" - -#include <stdint.h> - -#include <array> -#include <vector> - -#define IEEE80211_TX_MAX_RATES 4 - -struct hwsim_tx_rate { - signed char idx; - unsigned char count; -} __attribute__((__packed__)); - -enum class FrameType : uint8_t { - Unknown, - Ack, - Data, -}; - -enum class AccessCategory { - Voice, - Video, - BestEffort, - Background, -}; - -FrameType frameTypeFromByte(uint8_t byte); - -using Rates = std::array<hwsim_tx_rate, IEEE80211_TX_MAX_RATES>; - -class FrameInfo { -public: - FrameInfo() = default; - FrameInfo(const FrameInfo&) = default; - FrameInfo(FrameInfo&&) = default; - FrameInfo(const MacAddress& transmitter, - uint64_t cookie, - uint32_t flags, - uint32_t channel, - const hwsim_tx_rate* rates, - size_t numRates); - - FrameInfo& operator=(const FrameInfo&) = default; - FrameInfo& operator=(FrameInfo&&) = default; - - const Rates& rates() const { return mTxRates; } - Rates& rates() { return mTxRates; } - - const MacAddress& transmitter() const { return mTransmitter; } - uint64_t cookie() const { return mCookie; } - uint32_t flags() const { return mFlags; } - uint32_t channel() const { return mChannel; } - - bool shouldAck() const; - -private: - Rates mTxRates; - MacAddress mTransmitter; - uint64_t mCookie = 0; - uint32_t mFlags = 0; - uint32_t mChannel = 0; -}; - -class Frame { -public: - Frame() = default; - Frame(const uint8_t* data, size_t size); - Frame(const uint8_t* data, - size_t size, - const MacAddress& transmitter, - uint64_t cookie, - uint32_t flags, - uint32_t channel, - const hwsim_tx_rate* rates, - size_t numRates); - Frame(Frame&& other) = default; - - Frame& operator=(Frame&& other) = default; - - size_t size() const { return mData.size(); } - const uint8_t* data() const { return mData.data(); } - uint8_t* data() { return mData.data(); } - uint64_t cookie() const { return mInfo.cookie(); } - uint32_t flags() const { return mInfo.flags(); } - uint32_t channel() const { return mInfo.channel(); } - - Rates& rates() { return mInfo.rates(); } - const Rates& rates() const { return mInfo.rates(); } - - const Rates& initialRates() const { return mInitialTxRates; } - - // Increment the number of attempts made in the tx rates - bool incrementAttempts(); - bool hasRemainingAttempts(); - - // The transmitter as indicated by hwsim - const MacAddress& transmitter() const { return mInfo.transmitter(); } - // The source as indicated by the 802.11 frame - const MacAddress& source() const; - // The destination as indicated by the 802.11 frame - const MacAddress& destination() const; - - std::string str() const; - - const FrameInfo& info() const { return mInfo; } - FrameInfo& info() { return mInfo; } - - bool isBeacon() const; - bool isData() const; - bool isDataQoS() const; - - uint16_t getQoSControl() const; - - bool shouldAck() const { return mInfo.shouldAck(); } - - uint64_t calcNextTimeout(); - - void setRadioDestination(const MacAddress& destination) { - mRadioDestination = destination; - } - const MacAddress& radioDestination() const { return mRadioDestination; } -private: - Frame(const Frame&) = delete; - Frame& operator=(const Frame&) = delete; - - AccessCategory getAc() const; - - std::vector<uint8_t> mData; - FrameInfo mInfo; - MacAddress mRadioDestination; - Rates mInitialTxRates; - uint64_t mNextTimeout = 0; - // The contention winow determines how much time to back off on each retry. - // The contention window initial value and max value are determined by the - // access category of the frame. - uint32_t mContentionWindow = 0; - uint32_t mContentionWindowMax = 0; -}; - diff --git a/network/wifi_forwarder/frame_id.h b/network/wifi_forwarder/frame_id.h deleted file mode 100644 index 545693a2..00000000 --- a/network/wifi_forwarder/frame_id.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "macaddress.h" - -#include <string.h> - -struct FrameId { - FrameId() {} - FrameId(uint64_t cookie, const MacAddress& transmitter) - : cookie(cookie), transmitter(transmitter) { - } - FrameId(const FrameId&) = default; - FrameId(FrameId&&) = default; - - FrameId& operator=(const FrameId&) = default; - FrameId& operator=(FrameId&&) = default; - - uint64_t cookie; - MacAddress transmitter; -}; - -namespace std { -template<> struct hash<FrameId> { - size_t operator()(const FrameId& id) const { - size_t seed = 0; - hash_combine(seed, id.cookie); - hash_combine(seed, id.transmitter); - return seed; - } -}; -} - -inline bool operator==(const FrameId& left, const FrameId& right) { - return left.cookie == right.cookie && left.transmitter == right.transmitter; -} - -inline bool operator<(const FrameId& left, const FrameId& right) { - if (left.cookie < right.cookie) { - return true; - } - if (left.cookie > right.cookie) { - return false; - } - return memcmp(left.transmitter.addr, - right.transmitter.addr, - sizeof(left.transmitter.addr)) < 0; -} diff --git a/network/wifi_forwarder/hwsim.h b/network/wifi_forwarder/hwsim.h deleted file mode 100644 index 1a7b09b3..00000000 --- a/network/wifi_forwarder/hwsim.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -// mac80211_hwsim flags, from kernel drivers/net/wireless/mac80211_hwsim.h -#define BIT(num) (1UL << (num)) -enum hwsim_tx_control_flags { - HWSIM_TX_CTL_REQ_TX_STATUS = BIT(0), - HWSIM_TX_CTL_NO_ACK = BIT(1), - HWSIM_TX_STAT_ACK = BIT(2), -}; - -// mac80211_hwsim commands, from kernel drivers/net/wireless/mac80211_hwsim.h -enum HwSimCommand { - HWSIM_CMD_UNSPEC, - HWSIM_CMD_REGISTER, - HWSIM_CMD_FRAME, - HWSIM_CMD_TX_INFO_FRAME, - HWSIM_CMD_NEW_RADIO, - HWSIM_CMD_DEL_RADIO, - HWSIM_CMD_GET_RADIO, - __HWSIM_CMD_MAX, -}; - -// mac80211_hwsim attributes, from kernel drivers/net/wireless/mac80211_hwsim.h -enum HwSimAttribute { - HWSIM_ATTR_UNSPEC, - HWSIM_ATTR_ADDR_RECEIVER, - HWSIM_ATTR_ADDR_TRANSMITTER, - HWSIM_ATTR_FRAME, - HWSIM_ATTR_FLAGS, - HWSIM_ATTR_RX_RATE, - HWSIM_ATTR_SIGNAL, - HWSIM_ATTR_TX_INFO, - HWSIM_ATTR_COOKIE, - HWSIM_ATTR_CHANNELS, - HWSIM_ATTR_RADIO_ID, - HWSIM_ATTR_REG_HINT_ALPHA2, - HWSIM_ATTR_REG_CUSTOM_REG, - HWSIM_ATTR_REG_STRICT_REG, - HWSIM_ATTR_SUPPORT_P2P_DEVICE, - HWSIM_ATTR_USE_CHANCTX, - HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, - HWSIM_ATTR_RADIO_NAME, - HWSIM_ATTR_NO_VIF, - HWSIM_ATTR_FREQ, - __HWSIM_ATTR_MAX, -}; -#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) - diff --git a/network/wifi_forwarder/ieee80211.h b/network/wifi_forwarder/ieee80211.h deleted file mode 100644 index 6bcf2326..00000000 --- a/network/wifi_forwarder/ieee80211.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <net/ethernet.h> -#include <stdint.h> - -struct ieee80211_hdr { - uint16_t frame_control; - uint16_t duration_id; - uint8_t addr1[ETH_ALEN]; - uint8_t addr2[ETH_ALEN]; - uint8_t addr3[ETH_ALEN]; - uint16_t seq_ctrl; - uint8_t addr4[ETH_ALEN]; -} __attribute__((__packed__)); - diff --git a/network/wifi_forwarder/local_connection.cpp b/network/wifi_forwarder/local_connection.cpp deleted file mode 100644 index 1cebc17e..00000000 --- a/network/wifi_forwarder/local_connection.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "local_connection.h" - -#include "hwsim.h" -#include "log.h" -#include "macaddress.h" -#include "netlink_message.h" - -#include <net/ethernet.h> -#include <netlink/netlink.h> -#include <netlink/genl/ctrl.h> -#include <netlink/genl/genl.h> - -#include <utils/CallStack.h> - -#include <inttypes.h> -#include <stdlib.h> - -static const char kHwSimFamilyName[] = "MAC80211_HWSIM"; -static const int kHwSimVersion = 1; -static const unsigned int kDefaultSignalStrength = -50; -static const int kDefaultSocketBufferSize = 8 * (1 << 20); - -static uint32_t getSeqNum(struct nl_msg* msg) { - return nlmsg_hdr(msg)->nlmsg_seq; -} - -static int onSent(struct nl_msg* , void*) { - return NL_OK; -} - -static int onSeqCheck(struct nl_msg* msg, void*) { - uint32_t seq = getSeqNum(msg); - return seq == 0 ? NL_SKIP : NL_OK; -} - -LocalConnection::LocalConnection(OnFrameCallback onFrameCallback, - OnAckCallback onAckCallback, - OnErrorCallback onErrorCallback) - : mOnFrameCallback(onFrameCallback) - , mOnAckCallback(onAckCallback) - , mOnErrorCallback(onErrorCallback) { - -} - -Result LocalConnection::init(std::chrono::steady_clock::time_point now) { - Result res = mNetlinkSocket.init(); - if (!res) { return res; } - res = mNetlinkSocket.setOnMsgInCallback(staticOnMessage, this); - if (!res) { return res; } - res = mNetlinkSocket.setOnMsgOutCallback(onSent, this); - if (!res) { return res; } - res = mNetlinkSocket.setOnSeqCheckCallback(onSeqCheck, this); - if (!res) { return res; } - res = mNetlinkSocket.setOnAckCallback(staticOnAck, this); - if (!res) { return res; } - res = mNetlinkSocket.setOnErrorCallback(staticOnError, this); - if (!res) { return res; } - res = mNetlinkSocket.connectGeneric(); - if (!res) { return res; } - res = mNetlinkSocket.setBufferSizes(kDefaultSocketBufferSize, - kDefaultSocketBufferSize); - if (!res) { return res; } - - mNetlinkFamily = mNetlinkSocket.resolveNetlinkFamily(kHwSimFamilyName); - if (mNetlinkFamily < 0) { - return Result::error("Failed to resolve netlink family name: %s", - nl_geterror(mNetlinkFamily)); - } - - mPendingFrames.setCurrentTime(now); - mSequenceNumberCookies.setCurrentTime(now); - - mLastCacheTimeUpdate = now; - mLastCacheExpiration = now; - - return registerReceiver(); -} - -int LocalConnection::getFd() const { - return mNetlinkSocket.getFd(); -} - -bool LocalConnection::receive() { - return mNetlinkSocket.receive(); -} - -uint32_t LocalConnection::transferFrame(std::unique_ptr<Frame> frame, - const MacAddress& dest) { - NetlinkMessage msg; - - if (!msg.initGeneric(mNetlinkFamily, HWSIM_CMD_FRAME, kHwSimVersion)) { - ALOGE("LocalConnection transferFrame failed to init msg"); - return 0; - } - - frame->incrementAttempts(); - - if (!msg.addAttribute(HWSIM_ATTR_ADDR_RECEIVER, dest.addr, ETH_ALEN) || - !msg.addAttribute(HWSIM_ATTR_FRAME, frame->data(), frame->size()) || - !msg.addAttribute(HWSIM_ATTR_RX_RATE, 1u) || - !msg.addAttribute(HWSIM_ATTR_SIGNAL, kDefaultSignalStrength) || - !msg.addAttribute(HWSIM_ATTR_FREQ, frame->channel())) { - - ALOGE("LocalConnection transferFrame failed to set attrs"); - return 0; - } - - if (!mNetlinkSocket.send(msg)) { - return 0; - } - - // Store the radio destination for potential retransmissions. - frame->setRadioDestination(dest); - - uint32_t seqNum = msg.getSeqNum(); - uint64_t cookie = frame->cookie(); - FrameId id(cookie, frame->transmitter()); - mSequenceNumberCookies[seqNum] = id; - mPendingFrames[id] = std::move(frame); - - return seqNum; -} - -uint32_t LocalConnection::cloneFrame(const Frame& frame, - const MacAddress& dest) { - auto copy = std::make_unique<Frame>(frame.data(), - frame.size(), - frame.transmitter(), - frame.cookie(), - frame.flags(), - frame.channel(), - frame.rates().data(), - frame.rates().size()); - return transferFrame(std::move(copy), dest); -} - -bool LocalConnection::ackFrame(FrameInfo& info, bool success) { - NetlinkMessage msg; - - if (!msg.initGeneric(mNetlinkFamily, - HWSIM_CMD_TX_INFO_FRAME, - kHwSimVersion)) { - ALOGE("LocalConnection ackFrame failed to create msg"); - return false; - } - - uint32_t flags = info.flags(); - if (success) { - flags |= HWSIM_TX_STAT_ACK; - } - - const uint8_t* transmitter = info.transmitter().addr; - const Rates& rates = info.rates(); - if (!msg.addAttribute(HWSIM_ATTR_ADDR_TRANSMITTER, transmitter, ETH_ALEN) || - !msg.addAttribute(HWSIM_ATTR_TX_INFO, rates.data(), rates.size()) || - !msg.addAttribute(HWSIM_ATTR_FLAGS, flags) || - !msg.addAttribute(HWSIM_ATTR_SIGNAL, kDefaultSignalStrength) || - !msg.addAttribute(HWSIM_ATTR_COOKIE, info.cookie())) { - - ALOGE("LocalConnection ackFrame failed to set attributes"); - return false; - } - - if (!mNetlinkSocket.send(msg)) { - return false; - } - mPendingFrames.erase(FrameId(info.cookie(), info.transmitter())); - return true; -} - -std::chrono::steady_clock::time_point LocalConnection::getTimeout() const { - if (mRetryQueue.empty()) { - return std::chrono::steady_clock::time_point::max(); - } - return mRetryQueue.top().first; -} - -void LocalConnection::onTimeout(std::chrono::steady_clock::time_point now) { - - if (now - mLastCacheTimeUpdate > std::chrono::seconds(1)) { - // Only update the time once per second, there's no need for a super - // high resolution here. We just want to make sure these caches don't - // fill up over a long period of time. - mPendingFrames.setCurrentTime(now); - mSequenceNumberCookies.setCurrentTime(now); - mLastCacheTimeUpdate = now; - } - if (now - mLastCacheExpiration > std::chrono::seconds(10)) { - // Only expire entries every 10 seconds, this is an operation that has - // some cost to it and doesn't have to happen very often. - mPendingFrames.expireEntries(); - mSequenceNumberCookies.expireEntries(); - mLastCacheExpiration = now; - } - - while (!mRetryQueue.empty() && now >= mRetryQueue.top().first) { - FrameId id = mRetryQueue.top().second; - auto frameIt = mPendingFrames.find(id); - if (frameIt != mPendingFrames.end()) { - // Frame is still available, retry it - std::unique_ptr<Frame> frame = std::move(frameIt->second); - mPendingFrames.erase(frameIt); - MacAddress dest = frame->radioDestination(); - transferFrame(std::move(frame), dest); - } - mRetryQueue.pop(); - } -} - -Result LocalConnection::registerReceiver() { - NetlinkMessage msg; - - if (!msg.initGeneric(mNetlinkFamily, HWSIM_CMD_REGISTER, kHwSimVersion)) { - return Result::error("Failed to create register receiver message"); - } - - if (!mNetlinkSocket.send(msg)) { - return Result::error("Failed to send register receiver message"); - } - return Result::success(); -} - -int LocalConnection::staticOnMessage(struct nl_msg* msg, void* context) { - if (!context) { - return NL_SKIP; - } - auto connection = static_cast<LocalConnection*>(context); - return connection->onMessage(msg); -} - -int LocalConnection::staticOnAck(struct nl_msg* msg, void* context) { - if (!context) { - return NL_SKIP; - } - auto connection = static_cast<LocalConnection*>(context); - return connection->onAck(msg); -} - -int LocalConnection::staticOnError(struct sockaddr_nl* addr, - struct nlmsgerr* error, - void* context) { - if (!context) { - return NL_SKIP; - } - auto connection = static_cast<LocalConnection*>(context); - return connection->onError(addr, error); -} - -int LocalConnection::onMessage(struct nl_msg* msg) { - struct nlmsghdr* hdr = nlmsg_hdr(msg); - auto generic = reinterpret_cast<const struct genlmsghdr*>(nlmsg_data(hdr)); - - switch (generic->cmd) { - case HWSIM_CMD_FRAME: - return onFrame(msg); - } - return NL_OK; -} - -int LocalConnection::onFrame(struct nl_msg* msg) { - - struct nlmsghdr* hdr = nlmsg_hdr(msg); - std::unique_ptr<Frame> frame = parseFrame(hdr); - if (!frame) { - return NL_SKIP; - } - - mOnFrameCallback(std::move(frame)); - return NL_OK; -} - -std::unique_ptr<Frame> LocalConnection::parseFrame(struct nlmsghdr* hdr) { - struct nlattr* attrs[HWSIM_ATTR_MAX + 1]; - genlmsg_parse(hdr, 0, attrs, HWSIM_ATTR_MAX, nullptr); - if (!attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) { - ALOGE("Received cmd frame without transmitter address"); - return nullptr; - } - if (!attrs[HWSIM_ATTR_TX_INFO]) { - ALOGE("Received cmd frame without tx rates"); - return nullptr; - } - if (!attrs[HWSIM_ATTR_FREQ]) { - ALOGE("Recieved cmd frame without channel frequency"); - return nullptr; - } - - uint64_t cookie = nla_get_u64(attrs[HWSIM_ATTR_COOKIE]); - - const auto& source = *reinterpret_cast<const MacAddress*>( - nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER])); - - auto rates = reinterpret_cast<const hwsim_tx_rate*>( - nla_data(attrs[HWSIM_ATTR_TX_INFO])); - int rateLength = nla_len(attrs[HWSIM_ATTR_TX_INFO]); - // Make sure the length is valid, must be multiple of hwsim_tx_rate - if (rateLength <= 0 || (rateLength % sizeof(hwsim_tx_rate)) != 0) { - ALOGE("Invalid tx rate length %d", rateLength); - } - size_t numRates = static_cast<size_t>(rateLength) / sizeof(hwsim_tx_rate); - - int length = nla_len(attrs[HWSIM_ATTR_FRAME]); - auto data = reinterpret_cast<uint8_t*>(nla_data(attrs[HWSIM_ATTR_FRAME])); - - uint32_t flags = nla_get_u32(attrs[HWSIM_ATTR_FLAGS]); - - uint32_t channel = nla_get_u32(attrs[HWSIM_ATTR_FREQ]); - - return std::make_unique<Frame>(data, length, source, cookie, - flags, channel, rates, numRates); -} - -int LocalConnection::onAck(struct nl_msg* msg) { - struct nlmsghdr* hdr = nlmsg_hdr(msg); - uint32_t seqNum = hdr->nlmsg_seq; - auto cookie = mSequenceNumberCookies.find(seqNum); - if (cookie == mSequenceNumberCookies.end()) { - // This is not a frame we sent. This is fairly common for libnl's - // internal use so don't log this. - return NL_SKIP; - } - auto pendingFrame = mPendingFrames.find(cookie->second); - // We don't need to keep this around anymore, erase it. - mSequenceNumberCookies.erase(seqNum); - if (pendingFrame == mPendingFrames.end()) { - // We have no cookie associated with this sequence number. This might - // happen if the remote connection already acked the frame and removed - // the frame info. Consider this resolved. - return NL_SKIP; - } - - Frame* frame = pendingFrame->second.get(); - mOnAckCallback(frame->info()); - // Make sure to erase using the cookie instead of the iterator. The callback - // might have already erased this entry so the iterator could be invalid at - // this point. Instead of a fancy scheme of checking this just play it safe - // to allow the callback more freedom. - mPendingFrames.erase(cookie->second); - - return NL_OK; -} - -int LocalConnection::onError(struct sockaddr_nl*, struct nlmsgerr* error) { - struct nlmsghdr* hdr = &error->msg; - uint32_t seqNum = hdr->nlmsg_seq; - - auto idIt = mSequenceNumberCookies.find(seqNum); - if (idIt == mSequenceNumberCookies.end()) { - return NL_SKIP; - } - FrameId id = idIt->second; - // No need to keep the sequence number around anymore, it's expired and is - // no longer useful. - mSequenceNumberCookies.erase(idIt); - - auto frameIt = mPendingFrames.find(id); - if (frameIt == mPendingFrames.end()) { - return NL_SKIP; - } - Frame* frame = frameIt->second.get(); - - if (!frame->hasRemainingAttempts()) { - // This frame has used up all its attempts, there's nothing we can do - mOnErrorCallback(frame->info()); - mPendingFrames.erase(id); - return NL_SKIP; - } - // Store the frame in the retry queue - uint64_t timeout = frame->calcNextTimeout(); - auto deadline = std::chrono::steady_clock::now() + - std::chrono::microseconds(timeout); - mRetryQueue.emplace(deadline, id); - - return NL_SKIP; -} - diff --git a/network/wifi_forwarder/local_connection.h b/network/wifi_forwarder/local_connection.h deleted file mode 100644 index 9f3969a0..00000000 --- a/network/wifi_forwarder/local_connection.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "cache.h" -#include "frame.h" -#include "frame_id.h" -#include "macaddress.h" -#include "netlink_socket.h" -#include "result.h" - -#include <chrono> -#include <functional> -#include <memory> -#include <queue> - -struct MacAddress; - -class LocalConnection { -public: - using OnFrameCallback = std::function<void (std::unique_ptr<Frame>)>; - using OnAckCallback = std::function<void (FrameInfo&)>; - using OnErrorCallback = OnAckCallback; - - LocalConnection(OnFrameCallback onFrameCallback, - OnAckCallback onAckCallback, - OnErrorCallback onErrorCallback); - Result init(std::chrono::steady_clock::time_point now); - - int getFd() const; - bool receive(); - uint32_t cloneFrame(const Frame& frame, const MacAddress& destination); - uint32_t transferFrame(std::unique_ptr<Frame> frame, - const MacAddress& destination); - bool ackFrame(FrameInfo& info, bool success); - - std::chrono::steady_clock::time_point getTimeout() const; - void onTimeout(std::chrono::steady_clock::time_point now); - -private: - using Timestamp = std::chrono::steady_clock::time_point; - - Result registerReceiver(); - static int staticOnMessage(struct nl_msg* msg, void* context); - static int staticOnAck(struct nl_msg* msg, void* context); - static int staticOnError(struct sockaddr_nl* addr, - struct nlmsgerr* error, - void* context); - int onMessage(struct nl_msg* msg); - int onFrame(struct nl_msg* msg); - std::unique_ptr<Frame> parseFrame(struct nlmsghdr* hdr); - - int onAck(struct nl_msg* msg); - int onError(struct sockaddr_nl* addr, struct nlmsgerr* error); - bool sendFrameOnNetlink(const Frame& frame, const MacAddress& dest); - - OnFrameCallback mOnFrameCallback; - OnAckCallback mOnAckCallback; - OnErrorCallback mOnErrorCallback; - - NetlinkSocket mNetlinkSocket; - int mNetlinkFamily = -1; - - // [cookie,transmitter] -> frame. - Cache<FrameId, std::unique_ptr<Frame>> mPendingFrames; - // sequence number -> [cookie,transmitter] - Cache<uint32_t, FrameId> mSequenceNumberCookies; - - Timestamp mLastCacheTimeUpdate; - Timestamp mLastCacheExpiration; - - // A queue (using an ordered map) with the next timeout mapping to the - // cookie and transmitter of the frame to retry. This way we can easily - // determine when the next deadline is by looking at the first entry and we - // can quickly determine which frames to retry by starting at the beginning. - std::priority_queue<std::pair<Timestamp, FrameId>> mRetryQueue; -}; - diff --git a/network/wifi_forwarder/macaddress.h b/network/wifi_forwarder/macaddress.h deleted file mode 100644 index a9bcb660..00000000 --- a/network/wifi_forwarder/macaddress.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "hash.h" - -#include <linux/if_ether.h> -#include <stdint.h> -#include <string.h> - -// Format macros for printf, e.g. printf("MAC address: " PRIMAC, MACARG(mac)) -#define PRIMAC "%02x:%02x:%02x:%02x:%02x:%02x" -#define MACARG(x) (x)[0], (x)[1], (x)[2], (x)[3],(x)[4], (x)[5] - -struct MacAddress { - MacAddress() { - memset(addr, 0, sizeof(addr)); - } - MacAddress(uint8_t b1, uint8_t b2, uint8_t b3, - uint8_t b4, uint8_t b5, uint8_t b6) { - addr[0] = b1; addr[1] = b2; addr[2] = b3; - addr[3] = b4; addr[4] = b5; addr[5] = b6; - } - uint8_t addr[ETH_ALEN]; - bool isBroadcast() const { - return memcmp(addr, "\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ALEN) == 0; - } - bool isMulticast() const { - return addr[0] & 0x01; - } - bool empty() const { - return memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0; - } - uint8_t operator[](size_t index) const { - return addr[index]; - } -} __attribute__((__packed__)); - -namespace std { -template<> struct hash<MacAddress> { - size_t operator()(const MacAddress& addr) const { - size_t seed = 0; - // Treat the first 4 bytes as an uint32_t to save some computation - hash_combine(seed, *reinterpret_cast<const uint32_t*>(addr.addr)); - // And the remaining 2 bytes as an uint16_t - hash_combine(seed, *reinterpret_cast<const uint16_t*>(addr.addr + 4)); - return seed; - } -}; -} - -inline bool operator==(const MacAddress& left, const MacAddress& right) { - return memcmp(left.addr, right.addr, ETH_ALEN) == 0; -} - -inline bool operator!=(const MacAddress& left, const MacAddress& right) { - return memcmp(left.addr, right.addr, ETH_ALEN) != 0; -} - diff --git a/network/wifi_forwarder/main.cpp b/network/wifi_forwarder/main.cpp deleted file mode 100644 index 57127a94..00000000 --- a/network/wifi_forwarder/main.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "log.h" -#include "poller.h" -#include "wifi_forwarder.h" - -int main(int /*argc*/, char* /*argv*/[]) { - WifiForwarder forwarder; - Result res = forwarder.init(); - if (!res) { - ALOGE("%s", res.c_str()); - return 1; - } - - Poller poller; - poller.addPollable(&forwarder); - return poller.run(); -} - diff --git a/network/wifi_forwarder/netlink_message.cpp b/network/wifi_forwarder/netlink_message.cpp deleted file mode 100644 index 265c2968..00000000 --- a/network/wifi_forwarder/netlink_message.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "netlink_message.h" - -#include <netlink/genl/genl.h> -#include <netlink/msg.h> - -NetlinkMessage::NetlinkMessage() { -} - -NetlinkMessage::NetlinkMessage(NetlinkMessage&& other) { - std::swap(mMessage, other.mMessage); -} - -NetlinkMessage::~NetlinkMessage() { - if (mMessage) { - nlmsg_free(mMessage); - mMessage = nullptr; - } -} - -NetlinkMessage& NetlinkMessage::operator=(NetlinkMessage&& other) { - if (mMessage) { - nlmsg_free(mMessage); - mMessage = nullptr; - } - std::swap(mMessage, other.mMessage); - return *this; -} - -bool NetlinkMessage::initGeneric(int family, uint8_t command, int version) { - if (mMessage) { - return false; - } - - mMessage = nlmsg_alloc(); - if (!mMessage) { - return false; - } - - return genlmsg_put(mMessage, NL_AUTO_PORT, NL_AUTO_SEQ, family, 0, - NLM_F_REQUEST, command, version) != nullptr; -} - -uint32_t NetlinkMessage::getSeqNum() const { - return nlmsg_hdr(mMessage)->nlmsg_seq; -} diff --git a/network/wifi_forwarder/netlink_message.h b/network/wifi_forwarder/netlink_message.h deleted file mode 100644 index 53d97a96..00000000 --- a/network/wifi_forwarder/netlink_message.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "result.h" - -#include <netlink/netlink.h> - -#include <type_traits> - -class NetlinkMessage { -public: - NetlinkMessage(); - NetlinkMessage(NetlinkMessage&& other); - ~NetlinkMessage(); - - NetlinkMessage& operator=(NetlinkMessage&& other); - - bool initGeneric(int family, uint8_t command, int version); - - template<typename T, - typename = typename std::enable_if<!std::is_pointer<T>::value>::type> - bool addAttribute(int attribute, const T& value) { - return nla_put(mMessage, attribute, sizeof(T), &value) == 0; - } - template<typename T, - typename = typename std::enable_if<std::is_pointer<T>::value>::type> - bool addAttribute(int attribute, T data, size_t numElements) { - return nla_put(mMessage, - attribute, - sizeof(*data) * numElements, - data) == 0; - } - - uint32_t getSeqNum() const; - - struct nl_msg* get() { return mMessage; } - -private: - NetlinkMessage(const NetlinkMessage&) = delete; - NetlinkMessage& operator=(const NetlinkMessage&) = delete; - - struct nl_msg* mMessage = nullptr; -}; - diff --git a/network/wifi_forwarder/netlink_socket.cpp b/network/wifi_forwarder/netlink_socket.cpp deleted file mode 100644 index 5af66a56..00000000 --- a/network/wifi_forwarder/netlink_socket.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "netlink_socket.h" - -#include "log.h" -#include "netlink_message.h" - -#include <netlink/genl/ctrl.h> -#include <netlink/genl/genl.h> -#include <netlink/netlink.h> - -NetlinkSocket::NetlinkSocket() { -} - -NetlinkSocket::~NetlinkSocket() { - if (mSocket) { - nl_socket_free(mSocket); - mSocket = nullptr; - mCallback = nullptr; - } -} - -Result NetlinkSocket::init() { - if (mSocket || mCallback) { - return Result::error("Netlink socket already initialized"); - } - mCallback = nl_cb_alloc(NL_CB_CUSTOM); - if (!mCallback) { - return Result::error("Netlink socket failed to allocate callbacks"); - } - mSocket = nl_socket_alloc_cb(mCallback); - if (!mSocket) { - return Result::error("Failed to allocate netlink socket"); - } - return Result::success(); -} - -Result NetlinkSocket::setBufferSizes(int rxBufferSize, int txBufferSize) { - int res = nl_socket_set_buffer_size(mSocket, rxBufferSize, txBufferSize); - if (res != 0) { - return Result::error("Failed to set buffer sizes: %s", - nl_geterror(res)); - } - return Result::success(); -} - -Result NetlinkSocket::setOnMsgInCallback(int (*callback)(struct nl_msg*, void*), - void* context) { - if (nl_cb_set(mCallback, NL_CB_MSG_IN, NL_CB_CUSTOM, callback, context)) { - return Result::error("Failed to set OnMsgIn callback"); - } - return Result::success(); -} - -Result NetlinkSocket::setOnMsgOutCallback(int (*callback)(struct nl_msg*, - void*), - void* context) { - if (nl_cb_set(mCallback, NL_CB_MSG_OUT, NL_CB_CUSTOM, callback, context)) { - return Result::error("Failed to set OnMsgOut callback"); - } - return Result::success(); -} - -Result NetlinkSocket::setOnSeqCheckCallback(int (*callback)(struct nl_msg*, - void*), - void* context) { - if (nl_cb_set(mCallback, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, - callback, context)) { - return Result::error("Failed to set OnSeqCheck callback"); - } - return Result::success(); -} - -Result NetlinkSocket::setOnAckCallback(int (*callback)(struct nl_msg*, void*), - void* context) { - if (nl_cb_set(mCallback, NL_CB_ACK, NL_CB_CUSTOM, callback, context)) { - return Result::error("Failed to set OnAck callback"); - } - return Result::success(); -} - -Result NetlinkSocket::setOnErrorCallback(int (*callback)(struct sockaddr_nl*, - struct nlmsgerr*, - void*), - void* context) { - if (nl_cb_err(mCallback, NL_CB_CUSTOM, callback, context)) { - return Result::error("Failed to set OnError callback"); - } - return Result::success(); -} - -Result NetlinkSocket::connectGeneric() { - int status = genl_connect(mSocket); - if (status < 0) { - return Result::error("WifiNetlinkForwarder socket connect failed: %d", - status); - } - return Result::success(); -} - -int NetlinkSocket::resolveNetlinkFamily(const char* familyName) { - return genl_ctrl_resolve(mSocket, familyName); -} - -bool NetlinkSocket::send(NetlinkMessage& message) { - int status = nl_send_auto(mSocket, message.get()) >= 0; - if (status < 0) { - ALOGE("Failed to send on netlink socket: %s", nl_geterror(status)); - return false; - } - return true; -} - -bool NetlinkSocket::receive() { - int res = nl_recvmsgs_default(mSocket); - if (res != 0) { - ALOGE("Failed to receive messages on netlink socket: %s", - nl_geterror(res)); - return false; - } - return true; -} - -int NetlinkSocket::getFd() const { - if (!mSocket) { - return -1; - } - return nl_socket_get_fd(mSocket); -} diff --git a/network/wifi_forwarder/netlink_socket.h b/network/wifi_forwarder/netlink_socket.h deleted file mode 100644 index 9ff392c5..00000000 --- a/network/wifi_forwarder/netlink_socket.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "result.h" - -struct nl_cb; -struct nl_msg; -struct nl_sock; -struct nlmsgerr; -struct sockaddr_nl; - -class NetlinkMessage; - -class NetlinkSocket { -public: - NetlinkSocket(); - ~NetlinkSocket(); - - Result init(); - - /* Set the size of the receive buffer to |rxBufferSize| bytes and the - * transmit buffer to |txBufferSize| bytes. - */ - Result setBufferSizes(int rxBufferSize, int txBufferSize); - - Result setOnMsgInCallback(int (*callback)(struct nl_msg*, void*), - void* context); - Result setOnMsgOutCallback(int (*callback)(struct nl_msg*, void*), - void* context); - Result setOnSeqCheckCallback(int (*callback)(struct nl_msg*, void*), - void* context); - Result setOnAckCallback(int (*callback)(struct nl_msg*, void*), - void* context); - Result setOnErrorCallback(int (*callback)(struct sockaddr_nl*, - struct nlmsgerr*, - void*), - void* context); - - /* Connect socket to generic netlink. This needs to be done before generic - * netlink messages can be sent. After this is done the caller should use - * @resolveGenericNetlinkFamily to determine the generic family id to use. - * Then create NetlinkMessage's with that family id. - */ - Result connectGeneric(); - - /* Resolve a generic family name to a family identifier. This is used when - * sending generic netlink messages to indicate where the message should go. - * Examples of family names are "mac80211_hwsim" or "nl80211". - */ - int resolveNetlinkFamily(const char* familyName); - - /* Send a netlink message on this socket. */ - bool send(NetlinkMessage& message); - - /* Receive all pending message. This method does not return any messages, - * instead they will be provided through the callback set with - * setOnMsgInCallback. This callback will be called on the same thread as - * this method while this method is running. */ - bool receive(); - - int getFd() const; - -private: - struct nl_cb* mCallback = nullptr; - struct nl_sock* mSocket = nullptr; -}; - diff --git a/network/wifi_forwarder/pollable.h b/network/wifi_forwarder/pollable.h deleted file mode 100644 index 51724c05..00000000 --- a/network/wifi_forwarder/pollable.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <chrono> -#include <vector> - -#include <poll.h> - -/* An interface for pollable classes. - */ -class Pollable { -public: - using Clock = std::chrono::steady_clock; - using Timestamp = Clock::time_point; - virtual ~Pollable() = default; - - /* Get the poll data for the next poll loop. The implementation can place - * as many fds as needed in |fds|. - */ - virtual void getPollData(std::vector<pollfd>* fds) const = 0; - /* Get the timeout for the next poll loop. This should be a timestamp - * indicating when the timeout should be triggered. Note that this may - * be called at any time and any number of times for a poll loop so the - * deadline should not be adjusted in this call, a set deadline should - * just be returned. Note specifically that if a call to onReadAvailable - * modifies the deadline the timeout for the previous timestamp might not - * fire as the poller will check the timestamp AFTER onReadAvailable is - * called. - */ - virtual Timestamp getTimeout() const = 0; - /* Called when there is data available to read on an fd associated with - * the pollable. |fd| indicates which fd to read from. If the call returns - * false the poller will exit its poll loop with a return code of |status|. - */ - virtual bool onReadAvailable(int fd, int* status) = 0; - /* Called when an fd associated with the pollable is closed. |fd| indicates - * which fd was closed. If the call returns false the poller will exit its - * poll loop with a return code of |status|. - */ - virtual bool onClose(int fd, int* status) = 0; - /* Called when the timeout returned by getPollData has been reached. If - * the call returns false the poller will exit its poll loop with a return - * code of |status|. - */ - virtual bool onTimeout(Timestamp now, int* status) = 0; -}; - diff --git a/network/wifi_forwarder/poller.cpp b/network/wifi_forwarder/poller.cpp deleted file mode 100644 index 319dff4f..00000000 --- a/network/wifi_forwarder/poller.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "poller.h" - -#include "log.h" - -#include <errno.h> -#include <poll.h> -#include <signal.h> -#include <stdio.h> -#include <string.h> - -#include <unordered_map> -#include <vector> - -using std::chrono::duration_cast; - -static struct timespec* calculateTimeout(Pollable::Timestamp deadline, - struct timespec* ts) { - Pollable::Timestamp now = Pollable::Clock::now(); - if (deadline < Pollable::Timestamp::max()) { - if (deadline <= now) { - ts->tv_sec = 0; - ts->tv_nsec = 0; - return ts; - } - - auto timeout = deadline - now; - // Convert and round down to seconds - auto seconds = duration_cast<std::chrono::seconds>(timeout); - // Then subtract the seconds from the timeout and convert the remainder - auto nanos = duration_cast<std::chrono::nanoseconds>(timeout - seconds); - - ts->tv_sec = seconds.count(); - ts->tv_nsec = nanos.count(); - - return ts; - } - return nullptr; -} - -Poller::Poller() { -} - -void Poller::addPollable(Pollable* pollable) { - mPollables.push_back(pollable); -} - -int Poller::run() { - // Block all signals while we're running. This way we don't have to deal - // with things like EINTR. We then uses ppoll to set the original mask while - // polling. This way polling can be interrupted but socket writing, reading - // and ioctl remain interrupt free. If a signal arrives while we're blocking - // it it will be placed in the signal queue and handled once ppoll sets the - // original mask. This way no signals are lost. - sigset_t blockMask, mask; - int status = ::sigfillset(&blockMask); - if (status != 0) { - ALOGE("Unable to fill signal set: %s", strerror(errno)); - return errno; - } - status = ::sigprocmask(SIG_SETMASK, &blockMask, &mask); - if (status != 0) { - ALOGE("Unable to set signal mask: %s", strerror(errno)); - return errno; - } - - std::vector<struct pollfd> fds; - std::unordered_map<int, Pollable*> pollables; - while (true) { - fds.clear(); - pollables.clear(); - Pollable::Timestamp deadline = Pollable::Timestamp::max(); - for (auto& pollable : mPollables) { - size_t start = fds.size(); - pollable->getPollData(&fds); - Pollable::Timestamp pollableDeadline = pollable->getTimeout(); - // Create a map from each fd to the pollable - for (size_t i = start; i < fds.size(); ++i) { - pollables[fds[i].fd] = pollable; - } - if (pollableDeadline < deadline) { - deadline = pollableDeadline; - } - } - - struct timespec ts = { 0, 0 }; - struct timespec* tsPtr = calculateTimeout(deadline, &ts); - status = ::ppoll(fds.data(), fds.size(), tsPtr, &mask); - if (status < 0) { - if (errno == EINTR) { - // Interrupted, just keep going - continue; - } - // Actual error, time to quit - ALOGE("Polling failed: %s", strerror(errno)); - return errno; - } else if (status > 0) { - // Check for read or close events - for (const auto& fd : fds) { - if ((fd.revents & (POLLIN | POLLHUP)) == 0) { - // Neither POLLIN nor POLLHUP, not interested - continue; - } - auto pollable = pollables.find(fd.fd); - if (pollable == pollables.end()) { - // No matching fd, weird and unexpected - ALOGE("Poller could not find fd matching %d", fd.fd); - continue; - } - if (fd.revents & POLLIN) { - // This pollable has data available for reading - int status = 0; - if (!pollable->second->onReadAvailable(fd.fd, &status)) { - // The onReadAvailable handler signaled an exit - return status; - } - } - if (fd.revents & POLLHUP) { - // The fd was closed from the other end - int status = 0; - if (!pollable->second->onClose(fd.fd, &status)) { - // The onClose handler signaled an exit - return status; - } - } - } - } - // Check for timeouts - Pollable::Timestamp now = Pollable::Clock::now(); - for (const auto& pollable : mPollables) { - if (pollable->getTimeout() <= now) { - int status = 0; - if (!pollable->onTimeout(now, &status)) { - // The onTimeout handler signaled an exit - return status; - } - } - } - } - - return 0; -} diff --git a/network/wifi_forwarder/remote_connection.cpp b/network/wifi_forwarder/remote_connection.cpp deleted file mode 100644 index 7255e052..00000000 --- a/network/wifi_forwarder/remote_connection.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "remote_connection.h" - -#include "hwsim.h" -#include "frame.h" -#include "log.h" - -#include <errno.h> -#include <linux/kernel.h> -#include <netinet/in.h> -// Ignore warning about unused static qemu pipe function -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#include <qemu_pipe.h> -#pragma clang diagnostic pop -#include <sys/uio.h> -#include <unistd.h> - -static const char kQemuPipeName[] = "qemud:wififorward"; -static const size_t kReceiveBufferIncrement = 32768; -static const size_t kReceiveBufferMaxSize = 1 << 20; - -static const uint8_t kWifiForwardVersion = 0x01; -static const uint32_t kWifiForwardMagic = 0xD6C4B3A2; - -// This matches with the kernel constant IEEE80211_TX_MAX_RATES in -// include/net/mac80211.h in the kernel tree. -static const uint32_t kMaxNumRates = 4; - -struct WifiForwardHeader { - WifiForwardHeader(FrameType type, const MacAddress& transmitter, - uint32_t fullLength, uint64_t cookie, - uint32_t flags, uint32_t channel, uint32_t numRates, - const hwsim_tx_rate* txRates) - : magic(__cpu_to_le32(kWifiForwardMagic)) - , version(kWifiForwardVersion) - , type(static_cast<uint16_t>(type)) - , transmitter(transmitter) - , dataOffset(sizeof(WifiForwardHeader)) - , fullLength(__cpu_to_le32(fullLength)) - , cookie(__cpu_to_le64(cookie)) - , flags(__cpu_to_le32(flags)) - , channel(__cpu_to_le32(channel)) - , numRates(__cpu_to_le32(numRates)) { - memcpy(rates, txRates, std::min(numRates, kMaxNumRates)); - if (numRates < kMaxNumRates) { - memset(&rates[numRates], - 0, - sizeof(rates[0]) * (kMaxNumRates - numRates)); - } - } - - uint32_t magic; - uint8_t version; - uint8_t type; - MacAddress transmitter; - uint16_t dataOffset; - uint32_t fullLength; - uint64_t cookie; - uint32_t flags; - uint32_t channel; - uint32_t numRates; - hwsim_tx_rate rates[kMaxNumRates]; -} __attribute__((__packed__)); - -RemoteConnection::RemoteConnection(OnFrameCallback onFrameCallback, - OnAckCallback onAckCallback, - OnErrorCallback onErrorCallback) - : mOnFrameCallback(onFrameCallback) - , mOnAckCallback(onAckCallback) - , mOnErrorCallback(onErrorCallback) { - -} - -RemoteConnection::~RemoteConnection() { - if (mPipeFd != -1) { - ::close(mPipeFd); - mPipeFd = -1; - } -} - -Result RemoteConnection::init() { - if (mPipeFd != -1) { - return Result::error("RemoteConnetion already initialized"); - } - - mPipeFd = qemu_pipe_open(kQemuPipeName); - if (mPipeFd == -1) { - return Result::error("RemoteConnection failed to open pipe"); - } - return Result::success(); -} - -Pollable::Timestamp RemoteConnection::getTimeout() const { - // If there is no pipe return the deadline, we're going to retry, otherwise - // use an infinite timeout. - return mPipeFd == -1 ? mDeadline : Pollable::Timestamp::max(); -} - -void RemoteConnection::receive() { - size_t start = mBuffer.size(); - size_t newSize = start + kReceiveBufferIncrement; - if (newSize > kReceiveBufferMaxSize) { - // We've exceeded the maximum allowed size, drop everything we have so - // far and start over. This is most likely caused by some delay in - // injection or the injection failing in which case keeping old data - // around isn't going to be very useful. - ALOGE("RemoteConnection ran out of buffer space"); - newSize = kReceiveBufferIncrement; - start = 0; - } - mBuffer.resize(newSize); - - while (true) { - int result = ::read(mPipeFd, - mBuffer.data() + start, - mBuffer.size() - start); - if (result < 0) { - if (errno == EINTR) { - continue; - } - ALOGE("RemoteConnection failed to read to forward buffer: %s", - strerror(errno)); - // Return the buffer to its previous size - mBuffer.resize(start); - return; - } else if (result == 0) { - // Nothing received, nothing to write - // Return the buffer to its previous size - mBuffer.resize(start); - ALOGE("RemoteConnection did not receive anything to inject"); - return; - } - // Adjust the buffer size to match everything we recieved - mBuffer.resize(start + static_cast<size_t>(result)); - break; - } - - while (mBuffer.size() >= sizeof(WifiForwardHeader)) { - auto fwd = reinterpret_cast<WifiForwardHeader*>(mBuffer.data()); - if (__le32_to_cpu(fwd->magic) != kWifiForwardMagic) { - // We are not properly aligned, this can happen for the first read - // if the client or server happens to send something that's in the - // middle of a stream. Attempt to find the next packet boundary. - ALOGE("RemoteConnection found incorrect magic, finding next magic"); - uint32_t le32magic = __cpu_to_le32(kWifiForwardMagic); - auto next = reinterpret_cast<unsigned char*>( - ::memmem(mBuffer.data(), mBuffer.size(), - &le32magic, sizeof(le32magic))); - if (next) { - // We've found a possible candidate, erase everything before - size_t length = next - mBuffer.data(); - mBuffer.erase(mBuffer.begin(), mBuffer.begin() + length); - continue; - } else { - // There is no possible candidate, drop everything except the - // last three bytes. The last three bytes could possibly be the - // start of the next magic without actually triggering the - // search above. - if (mBuffer.size() > 3) { - mBuffer.erase(mBuffer.begin(), mBuffer.end() - 3); - } - // In this case there is nothing left to parse so just return - // right away. - return; - } - } - // Check if we support this version - if (fwd->version != kWifiForwardVersion) { - // Unsupported version - if (!mReportedVersionMismatches.test(fwd->version)) { - // Only report these once per version or this might become - // very spammy. - ALOGE("RemoteConnection encountered unknown version %u", - fwd->version); - mReportedVersionMismatches.set(fwd->version); - } - // Drop the magic from the buffer and attempt to find the next magic - mBuffer.erase(mBuffer.begin(), mBuffer.begin() + 4); - continue; - } - // The length according to the wifi forward header - const uint32_t fullLength = __le32_to_cpu(fwd->fullLength); - const uint16_t offset = __le16_to_cpu(fwd->dataOffset); - if (offset < sizeof(WifiForwardHeader) || offset > fullLength) { - // The frame offset is not large enough to go past the header - // or it's outside of the bounds of the length of the frame. - ALOGE("Invalid data offset in header %u, full length is %u", - offset, fullLength); - // Erase the magic and try again - mBuffer.erase(mBuffer.begin(), mBuffer.begin() + 4); - continue; - } - const size_t frameLength = fullLength - offset; - - if (fullLength > mBuffer.size()) { - // We have not received enough data yet, wait for more to arrive. - return; - } - - FrameType type = frameTypeFromByte(fwd->type); - if (frameLength == 0 && type != FrameType::Ack) { - ALOGE("Received empty frame for non-ack frame"); - return; - } - unsigned char* frameData = mBuffer.data() + offset; - if (type == FrameType::Ack) { - FrameInfo info(fwd->transmitter, - __le64_to_cpu(fwd->cookie), - __le32_to_cpu(fwd->flags), - __le32_to_cpu(fwd->channel), - fwd->rates, - __le32_to_cpu(fwd->numRates)); - - if (info.flags() & HWSIM_TX_STAT_ACK) { - mOnAckCallback(info); - } else { - mOnErrorCallback(info); - } - } else if (type == FrameType::Data) { - auto frame = std::make_unique<Frame>(frameData, - frameLength, - fwd->transmitter, - __le64_to_cpu(fwd->cookie), - __le32_to_cpu(fwd->flags), - __le32_to_cpu(fwd->channel), - fwd->rates, - __le32_to_cpu(fwd->numRates)); - mOnFrameCallback(std::move(frame)); - } else { - ALOGE("Received unknown message type %u from remote", - static_cast<uint8_t>(fwd->type)); - } - - mBuffer.erase(mBuffer.begin(), mBuffer.begin() + fullLength); - } -} - -bool RemoteConnection::sendFrame(std::unique_ptr<Frame> frame) { - if (mPipeFd == -1) { - ALOGE("RemoteConnection unable to forward data, pipe not open"); - return false; - } - - WifiForwardHeader header(FrameType::Data, - frame->transmitter(), - frame->size() + sizeof(WifiForwardHeader), - frame->cookie(), - frame->flags(), - frame->channel(), - frame->rates().size(), - frame->rates().data()); -#if 1 - constexpr size_t count = 2; - struct iovec iov[count]; - iov[0].iov_base = &header; - iov[0].iov_len = sizeof(header); - iov[1].iov_base = frame->data(); - iov[1].iov_len = frame->size(); - - size_t totalSize = iov[0].iov_len + iov[1].iov_len; - - size_t current = 0; - for (;;) { - ssize_t written = ::writev(mPipeFd, iov + current, count - current); - if (written < 0) { - ALOGE("RemoteConnection failed to write to pipe: %s", - strerror(errno)); - return false; - } - if (static_cast<size_t>(written) == totalSize) { - // Optimize for most common case, everything was written - break; - } - totalSize -= written; - // Determine how much is left to write after this - while (current < count && written >= iov[current].iov_len) { - written -= iov[current++].iov_len; - } - if (current == count) { - break; - } - iov[current].iov_base = - reinterpret_cast<char*>(iov[current].iov_base) + written; - iov[current].iov_len -= written; - } -#else - if (!WriteFully(mPipeFd, &header, sizeof(header))) { - ALOGE("RemoteConnection failed to write to pipe: %s", strerror(errno)); - return false; - } - - if (!WriteFully(mPipeFd, frame->data(), frame->size())) { - ALOGE("RemoteConnection failed to write to pipe: %s", strerror(errno)); - return false; - } -#endif - return true; -} - -bool RemoteConnection::ackFrame(FrameInfo& info, bool success) { - uint32_t flags = info.flags(); - if (success) { - flags |= HWSIM_TX_STAT_ACK; - } - WifiForwardHeader header(FrameType::Ack, - info.transmitter(), - sizeof(WifiForwardHeader), - info.cookie(), - flags, - info.channel(), - info.rates().size(), - info.rates().data()); - - if (!WriteFully(mPipeFd, &header, sizeof(header))) { - ALOGE("RemoteConnection failed to write to pipe: %s", strerror(errno)); - return false; - } - return true; -} diff --git a/network/wifi_forwarder/remote_connection.h b/network/wifi_forwarder/remote_connection.h deleted file mode 100644 index 94c7e36d..00000000 --- a/network/wifi_forwarder/remote_connection.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "frame.h" -#include "pollable.h" -#include "result.h" - -#include <bitset> -#include <functional> -#include <memory> -#include <vector> - -struct MacAddress; - -class RemoteConnection { -public: - using OnFrameCallback = std::function<void (std::unique_ptr<Frame>)>; - using OnAckCallback = std::function<void (FrameInfo&)>; - using OnErrorCallback = OnAckCallback; - - RemoteConnection(OnFrameCallback onFrameCallback, - OnAckCallback onAckCallback, - OnErrorCallback onErrorCallback); - ~RemoteConnection(); - - Result init(); - - int getFd() const { return mPipeFd; } - Pollable::Timestamp getTimeout() const; - void receive(); - bool sendFrame(std::unique_ptr<Frame> frame); - bool ackFrame(FrameInfo& info, bool success); - -private: - RemoteConnection(const RemoteConnection&) = delete; - RemoteConnection& operator=(const RemoteConnection&) = delete; - - OnFrameCallback mOnFrameCallback; - OnAckCallback mOnAckCallback; - OnErrorCallback mOnErrorCallback; - - Pollable::Timestamp mDeadline = Pollable::Timestamp::max(); - std::vector<unsigned char> mBuffer; - int mPipeFd = -1; - std::bitset<256> mReportedVersionMismatches; -}; - diff --git a/network/wifi_forwarder/wifi_forwarder.cpp b/network/wifi_forwarder/wifi_forwarder.cpp deleted file mode 100644 index b56c7cdb..00000000 --- a/network/wifi_forwarder/wifi_forwarder.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wifi_forwarder.h" - -#include "frame.h" -#include "log.h" - -static constexpr bool kDebugTraffic = false; -static constexpr bool kDebugBeaconTraffic = false; - -// How many seconds to keep aliases alive for. Since this is used to keep track -// of randomized MAC addresses they will expire after a while. Set the value -// pretty high to ensure that we don't accidentally lose entries just because -// there's not a lot of frames going through. -static constexpr auto kAliasesCacheTimeout = std::chrono::hours(8); - -WifiForwarder::WifiForwarder() - : mAliases(kAliasesCacheTimeout) - , mLocalConnection([this](std::unique_ptr<Frame> frame) { - forwardFrame(std::move(frame), RadioType::Local); - }, - [this](FrameInfo& info) { onAck(info, true); }, - [this](FrameInfo& info) { onAck(info, false); }) - , mRemoteConnection([this](std::unique_ptr<Frame> frame) { - forwardFrame(std::move(frame), RadioType::Remote); - }, - [this](FrameInfo& info) { onAck(info, true); }, - [this](FrameInfo& info) { onAck(info, false); }) { -} - -Result WifiForwarder::init() { - auto now = Pollable::Clock::now(); - Result res = mRemoteConnection.init(); - if (!res) { - // It's OK if this fails, the emulator might not have been started with - // this feature enabled. If it's not enabled we'll try again later. If - // this does not succeed we don't need to perform the rest of the - // initialization either. Just let WiFi work the same as normal. - ALOGE("RemoteConnection failed to initialize: %s", res.c_str()); - mInitDeadline = now + std::chrono::minutes(1); - return Result::success(); - } - - mAliases.setCurrentTime(now); - res = mLocalConnection.init(now); - if (!res) { - return res; - } - mDeadline = now + std::chrono::seconds(1); - return Result::success(); -} - -void WifiForwarder::getPollData(std::vector<pollfd>* fds) const { - int fd = mLocalConnection.getFd(); - if (fd >= 0) { - struct pollfd pfd = { fd, POLLIN, 0 }; - fds->push_back(pfd); - } - fd = mRemoteConnection.getFd(); - if (fd >= 0) { - struct pollfd pfd = { fd, POLLIN, 0 }; - fds->push_back(pfd); - } -} - -Pollable::Timestamp WifiForwarder::getTimeout() const { - if (mRemoteConnection.getFd() == -1) { - return mInitDeadline; - } - return std::min(mLocalConnection.getTimeout(), mDeadline); -} - -bool WifiForwarder::onReadAvailable(int fd, int* /*status*/) { - if (fd == mRemoteConnection.getFd()) { - mRemoteConnection.receive(); - } else if (fd == mLocalConnection.getFd()) { - mLocalConnection.receive(); - } - return true; -} - -bool WifiForwarder::onClose(int /*fd*/, int* /*status*/) { - ALOGE("WifiForwarder socket closed unexpectedly"); - return false; -} - -bool WifiForwarder::onTimeout(Timestamp now, int* /*status*/) { - bool success = true; - if (now >= mInitDeadline) { - Result res = init(); - success = res.isSuccess(); - if (mRemoteConnection.getFd() == -1) { - // Remote connection not set up by init, try again later - mInitDeadline = now + std::chrono::minutes(1); - } - } - mLocalConnection.onTimeout(now); - if (now >= mDeadline) { - mDeadline += std::chrono::seconds(1); - mAliases.setCurrentTime(now); - mAliases.expireEntries(); - } - return success; -} - -const char* WifiForwarder::radioTypeToStr(RadioType type) const { - switch (type) { - case RadioType::Unknown: - return "Unknown"; - case RadioType::Local: - return "Local"; - case RadioType::Remote: - return "Remote"; - } -} - -void WifiForwarder::onAck(FrameInfo& info, bool success) { - RadioType type = mRadios[info.transmitter()]; - if (type == RadioType::Remote) { - if (kDebugTraffic) { - ALOGE("] ACK -] " PRIMAC " [ %" PRIu64 " ] success: %s", - MACARG(info.transmitter()), info.cookie(), - success ? "true" : "false"); - } - if (!mRemoteConnection.ackFrame(info, success)) { - ALOGE("WifiForwarder failed to ack remote frame"); - } - } else if (type == RadioType::Local) { - if (kDebugTraffic) { - ALOGE("> ACK -> " PRIMAC " [ %" PRIu64 " ] success: %s", - MACARG(info.transmitter()), info.cookie(), - success ? "true" : "false"); - } - if (!mLocalConnection.ackFrame(info, success)) { - ALOGE("WifiForwarder failed to ack local frame"); - } - } else { - ALOGE("Unknown transmitter in ack: " PRIMAC, - MACARG(info.transmitter())); - } -} - -void WifiForwarder::forwardFrame(std::unique_ptr<Frame> frame, - RadioType sourceType) { - if (kDebugTraffic) { - if (!frame->isBeacon() || kDebugBeaconTraffic) { - bool isRemote = sourceType == RadioType::Remote; - ALOGE("%c " PRIMAC " -%c " PRIMAC " %s", - isRemote ? '[' : '<', isRemote ? ']' : '>', - MACARG(frame->source()), - MACARG(frame->destination()), - frame->str().c_str()); - } - } - - const MacAddress& source = frame->source(); - const MacAddress& transmitter = frame->transmitter(); - const MacAddress& destination = frame->destination(); - auto& currentType = mRadios[transmitter]; - if (currentType != RadioType::Unknown && currentType != sourceType) { - ALOGE("Replacing type for MAC " PRIMAC " of type %s with type %s, " - "this might indicate duplicate MACs on different emulators", - MACARG(source), radioTypeToStr(currentType), - radioTypeToStr(sourceType)); - } - currentType = sourceType; - mAliases[source] = transmitter; - - bool isMulticast = destination.isMulticast(); - bool sendOnRemote = isMulticast; - for (const auto& radio : mRadios) { - const MacAddress& radioAddress = radio.first; - RadioType radioType = radio.second; - if (radioAddress == transmitter) { - // Don't send back to the transmitter - continue; - } - if (sourceType == RadioType::Remote && radioType == RadioType::Remote) { - // Don't forward frames back to the remote, the remote will have - // taken care of this. - continue; - } - bool forward = false; - if (isMulticast || destination == radioAddress) { - // The frame is either multicast or directly intended for this - // radio. Forward it. - forward = true; - } else { - auto alias = mAliases.find(destination); - if (alias != mAliases.end() && alias->second == radioAddress) { - // The frame is destined for an address that is a known alias - // for this radio. - forward = true; - } - } - uint32_t seq = 0; - if (forward) { - switch (radioType) { - case RadioType::Unknown: - ALOGE("Attempted to forward frame to unknown radio type"); - break; - case RadioType::Local: - if (kDebugTraffic) { - if (!frame->isBeacon() || kDebugBeaconTraffic) { - ALOGE("> " PRIMAC " -> " PRIMAC " %s", - MACARG(frame->source()), - MACARG(frame->destination()), - frame->str().c_str()); - } - } - if (isMulticast) { - // Clone the frame, it might be reused - seq = mLocalConnection.cloneFrame(*frame, radioAddress); - } else { - // This frame has a specific destination, move it - seq = mLocalConnection.transferFrame(std::move(frame), - radioAddress); - // Return so that we don't accidentally reuse the frame. - // This should be safe now because it's a unicast frame - // so it should not be sent to multiple radios. - return; - } - break; - case RadioType::Remote: - sendOnRemote = true; - break; - } - } - } - if (sendOnRemote && sourceType != RadioType::Remote) { - if (kDebugTraffic) { - if (!frame->isBeacon() || kDebugBeaconTraffic) { - ALOGE("] " PRIMAC " -] " PRIMAC " %s", - MACARG(frame->source()), - MACARG(frame->destination()), - frame->str().c_str()); - } - } - // This is either a multicast message or destined for a radio known to - // be a remote. No need to send multiple times to a remote, the remote - // will handle that on its own. - mRemoteConnection.sendFrame(std::move(frame)); - } -} diff --git a/network/wifi_forwarder/wifi_forwarder.h b/network/wifi_forwarder/wifi_forwarder.h deleted file mode 100644 index dfe57d88..00000000 --- a/network/wifi_forwarder/wifi_forwarder.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "cache.h" -#include "frame.h" -#include "local_connection.h" -#include "macaddress.h" -#include "pollable.h" -#include "remote_connection.h" -#include "result.h" - -#include <unordered_map> - -class WifiForwarder : public Pollable { -public: - WifiForwarder(); - virtual ~WifiForwarder() = default; - Result init(); - - // Pollable interface - void getPollData(std::vector<pollfd>* fds) const override; - Timestamp getTimeout() const override; - bool onReadAvailable(int fd, int* status) override; - bool onClose(int fd, int* status) override; - bool onTimeout(Timestamp now, int* status) override; -private: - enum class RadioType { - Unknown, - Local, - Remote - }; - - const char* radioTypeToStr(RadioType type) const; - - void onAck(FrameInfo& info, bool success); - - void forwardFrame(std::unique_ptr<Frame> frame, RadioType sourceType); - - std::unordered_map<MacAddress, RadioType> mRadios; - Cache<MacAddress, MacAddress> mAliases; - LocalConnection mLocalConnection; - RemoteConnection mRemoteConnection; - Pollable::Timestamp mInitDeadline = Pollable::Timestamp::max(); - Pollable::Timestamp mDeadline = Pollable::Timestamp::max(); -}; - diff --git a/power/Android.mk b/power/Android.mk index 27f325c5..3466c540 100644 --- a/power/Android.mk +++ b/power/Android.mk @@ -29,6 +29,7 @@ LOCAL_SHARED_LIBRARIES := \ libbase \ libcutils \ libhidlbase \ + libhidltransport \ liblog \ libutils \ android.hardware.power@1.1 \ diff --git a/ril/Android.mk b/ril/Android.mk index a5423cef..cb5f31a9 100644 --- a/ril/Android.mk +++ b/ril/Android.mk @@ -9,7 +9,6 @@ LOCAL_SRC_FILES:= \ reference-ril.c \ atchannel.c \ if_monitor.cpp \ - ipv6_monitor.cpp \ misc.c \ at_tok.c diff --git a/ril/if_monitor.cpp b/ril/if_monitor.cpp index 87681f57..289477d2 100644 --- a/ril/if_monitor.cpp +++ b/ril/if_monitor.cpp @@ -16,9 +16,7 @@ #include "if_monitor.h" -#include <arpa/inet.h> #include <errno.h> -#include <ifaddrs.h> #include <linux/rtnetlink.h> #include <net/if.h> #include <poll.h> @@ -32,7 +30,6 @@ #include <mutex> #include <thread> #include <unordered_map> -#include <unordered_set> #include <vector> #define LOG_TAG "RIL-IFMON" @@ -59,18 +56,6 @@ static size_t addrLength(int addrFamily) { } } -static const void* getSockAddrData(const struct sockaddr* addr) { - switch (addr->sa_family) { - case AF_INET: - return &reinterpret_cast<const struct sockaddr_in*>(addr)->sin_addr; - case AF_INET6: - return - &reinterpret_cast<const struct sockaddr_in6*>(addr)->sin6_addr; - default: - return nullptr; - } -} - bool operator==(const struct ifAddress& left, const struct ifAddress& right) { // The prefix length does not factor in to whether two addresses are the // same or not. Only the family and the address data. This matches the @@ -148,75 +133,32 @@ public: mThread = std::make_unique<std::thread>([this]() { run(); }); } - void requestAddresses() { - struct ifaddrs* addresses = nullptr; - - if (getifaddrs(&addresses) != 0) { - RLOGE("Unable to retrieve list of interfaces, cannot get initial " - "interface addresses: %s", strerror(errno)); - return; - } - - for (struct ifaddrs* cur = addresses; cur; cur = cur->ifa_next) { - if (cur->ifa_name == nullptr || - cur->ifa_addr == nullptr || - cur->ifa_netmask == nullptr) { - // Interface doesn't have all the information we need. Rely on - // the netlink notification to catch this interface later if it - // is configured correctly. - continue; - } - if (cur->ifa_flags & IFF_LOOPBACK) { - // Not interested in loopback devices, they will never be radio - // interfaces. - continue; - } - unsigned int ifIndex = if_nametoindex(cur->ifa_name); - if (ifIndex == 0) { - RLOGE("Encountered interface %s with no index: %s", - cur->ifa_name, strerror(errno)); - continue; - } - ifAddress addr; - addr.family = cur->ifa_addr->sa_family; - addr.prefix = getPrefix(cur->ifa_netmask); - memcpy(addr.addr, - getSockAddrData(cur->ifa_addr), - addrLength(cur->ifa_addr->sa_family)); - mAddresses[ifIndex].push_back(addr); - } - freeifaddrs(addresses); - - if (mOnAddressChangeCallback) { - for (const auto& ifAddr : mAddresses) { - mOnAddressChangeCallback(ifAddr.first, - ifAddr.second.data(), - ifAddr.second.size()); + void requestAddress() { + struct { + struct nlmsghdr hdr; + struct ifaddrmsg msg; + char padding[16]; + } request; + + memset(&request, 0, sizeof(request)); + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg)); + request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; + request.hdr.nlmsg_type = RTM_GETADDR; + + int status = ::send(mSocketFd, &request, request.hdr.nlmsg_len, 0); + if (status < 0 || + static_cast<unsigned int>(status) != request.hdr.nlmsg_len) { + if (status < 0) { + RLOGE("Failed to send netlink request: %s", strerror(errno)); + } else { + RLOGE("Short send only sent %d out of %d bytes", + status, (int)request.hdr.nlmsg_len); } } } - int getPrefix(const struct sockaddr* addr) { - // This uses popcnt, a built-in instruction on some CPUs, to count - // the number of bits in a 32-bit word. The number of bits in a netmask - // equals the width of the prefix. For example a netmask of - // 255.255.255.0 has 24 bits set and that's also its width. - if (addr->sa_family == AF_INET) { - auto v4 = reinterpret_cast<const struct sockaddr_in*>(addr); - return __builtin_popcount(v4->sin_addr.s_addr); - } else if (addr->sa_family == AF_INET6) { - auto v6 = reinterpret_cast<const struct sockaddr_in6*>(addr); - // Copy to our own array to avoid aliasing - uint64_t words[2]; - memcpy(words, v6->sin6_addr.s6_addr, sizeof(words)); - return __builtin_popcountll(words[0]) + - __builtin_popcountll(words[1]); - } - return 0; - } - void run() { - requestAddresses(); + requestAddress(); std::vector<struct pollfd> fds(2); fds[0].events = POLLIN; @@ -309,16 +251,11 @@ private: RLOGE("Received message type %d", (int)hdr->nlmsg_type); break; } - hdr = NLMSG_NEXT(hdr, length); + NLMSG_NEXT(hdr, length); } } } - std::string getInterfaceName(unsigned int ifIndex) { - char buffer[IF_NAMESIZE] = { '\0' }; - return if_indextoname(ifIndex, buffer); - } - void handleAddressChange(const struct nlmsghdr* hdr) { if (!mOnAddressChangeCallback) { return; diff --git a/ril/ipv6_monitor.cpp b/ril/ipv6_monitor.cpp deleted file mode 100644 index 8d577bc4..00000000 --- a/ril/ipv6_monitor.cpp +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ipv6_monitor.h" - -#include <errno.h> -#include <linux/filter.h> -#include <net/if.h> -#include <netinet/ether.h> -#include <netinet/icmp6.h> -#include <netinet/ip6.h> -#include <poll.h> -#include <string.h> -#include <unistd.h> - -#include <array> -#include <mutex> -#include <string> -#include <thread> -#include <unordered_set> -#include <vector> - -#define LOG_TAG "RIL-IPV6MON" -#include <utils/Log.h> - -static constexpr size_t kReadBufferSize = 32768; - -static constexpr size_t kRecursiveDnsOptHeaderSize = 8; - -static constexpr size_t kControlClient = 0; -static constexpr size_t kControlServer = 1; - -static constexpr char kMonitorAckCommand = '\1'; -static constexpr char kMonitorStopCommand = '\2'; - -// The amount of time to wait before trying to initialize interface again if -// it's not ready when rild starts. -static constexpr int kDeferredTimeoutMilliseconds = 1000; - -bool operator==(const in6_addr& left, const in6_addr& right) { - return ::memcmp(left.s6_addr, right.s6_addr, sizeof(left.s6_addr)) == 0; -} - -bool operator!=(const in6_addr& left, const in6_addr& right) { - return ::memcmp(left.s6_addr, right.s6_addr, sizeof(left.s6_addr)) != 0; -} - -template<class T> -static inline void hash_combine(size_t& seed, const T& value) { - std::hash<T> hasher; - seed ^= hasher(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2); -} - -namespace std { -template<> struct hash<in6_addr> { - size_t operator()(const in6_addr& ad) const { - size_t seed = 0; - hash_combine(seed, *reinterpret_cast<const uint32_t*>(&ad.s6_addr[0])); - hash_combine(seed, *reinterpret_cast<const uint32_t*>(&ad.s6_addr[4])); - hash_combine(seed, *reinterpret_cast<const uint32_t*>(&ad.s6_addr[8])); - hash_combine(seed, *reinterpret_cast<const uint32_t*>(&ad.s6_addr[12])); - return seed; - } -}; -} // namespace std - -static constexpr uint32_t kIpTypeOffset = offsetof(ip6_hdr, ip6_nxt); -static constexpr uint32_t kIcmpTypeOffset = sizeof(ip6_hdr) + - offsetof(icmp6_hdr, icmp6_type); - -// This is BPF program that will filter out anything that is not an NDP router -// advertisement. It's a very basic assembler syntax. The jumps indicate how -// many instructions to jump in addition to the automatic increment of the -// program counter. So a jump statement with a zero means to go to the next -// instruction, a value of 3 means that the next instruction will be the 4th -// after the current one. -static const struct sock_filter kNdpFilter[] = { - // Load byte at absolute address kIpTypeOffset - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIpTypeOffset), - // Jump, if byte is IPPROTO_ICMPV6 jump 0 instructions, if not jump 3. - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3), - // Load byte at absolute address kIcmpTypeOffset - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIcmpTypeOffset), - // Jump, if byte is ND_ROUTER_ADVERT jump 0 instructions, if not jump 1 - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1), - // Return the number of bytes to accept, accept all of them - BPF_STMT(BPF_RET | BPF_K, std::numeric_limits<uint32_t>::max()), - // Accept zero bytes, this is where the failed jumps go - BPF_STMT(BPF_RET | BPF_K, 0) -}; -static constexpr size_t kNdpFilterSize = - sizeof(kNdpFilter) / sizeof(kNdpFilter[0]); - -class Ipv6Monitor { -public: - Ipv6Monitor(const char* interfaceName); - ~Ipv6Monitor(); - - enum class InitResult { - Error, - Deferred, - Success, - }; - InitResult init(); - void setCallback(ipv6MonitorCallback callback); - void runAsync(); - void stop(); - -private: - InitResult initInterfaces(); - void run(); - void onReadAvailable(); - - ipv6MonitorCallback mMonitorCallback; - - in6_addr mGateway; - std::unordered_set<in6_addr> mDnsServers; - - std::unique_ptr<std::thread> mThread; - std::mutex mThreadMutex; - - std::string mInterfaceName; - int mSocketFd; - int mControlSocket[2]; - int mPollTimeout = -1; - bool mFullyInitialized = false; -}; - -Ipv6Monitor::Ipv6Monitor(const char* interfaceName) : - mMonitorCallback(nullptr), - mInterfaceName(interfaceName), - mSocketFd(-1) { - memset(&mGateway, 0, sizeof(mGateway)); - mControlSocket[0] = -1; - mControlSocket[1] = -1; -} - -Ipv6Monitor::~Ipv6Monitor() { - for (int& fd : mControlSocket) { - if (fd != -1) { - ::close(fd); - fd = -1; - } - } - if (mSocketFd != -1) { - ::close(mSocketFd); - mSocketFd = -1; - } -} - -Ipv6Monitor::InitResult Ipv6Monitor::init() { - if (mSocketFd != -1) { - RLOGE("Ipv6Monitor already initialized"); - return InitResult::Error; - } - - if (::socketpair(AF_UNIX, SOCK_DGRAM, 0, mControlSocket) != 0) { - RLOGE("Ipv6Monitor failed to create control socket pair: %s", - strerror(errno)); - return InitResult::Error; - } - - mSocketFd = ::socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, ETH_P_IPV6); - if (mSocketFd == -1) { - RLOGE("Ipv6Monitor failed to open socket: %s", strerror(errno)); - return InitResult::Error; - } - // If interface initialization fails we'll retry later - return initInterfaces(); -} - -void Ipv6Monitor::setCallback(ipv6MonitorCallback callback) { - mMonitorCallback = callback; -} - -Ipv6Monitor::InitResult Ipv6Monitor::initInterfaces() { - if (mFullyInitialized) { - RLOGE("Ipv6Monitor already initialized"); - return InitResult::Error; - } - struct ifreq request; - memset(&request, 0, sizeof(request)); - strlcpy(request.ifr_name, mInterfaceName.c_str(), sizeof(request.ifr_name)); - - // Set the ALLMULTI flag so we can capture multicast traffic - int status = ::ioctl(mSocketFd, SIOCGIFFLAGS, &request); - if (status != 0) { - if (errno == ENODEV) { - // It is not guaranteed that the network is entirely set up by the - // time rild has started. If that's the case the radio interface - // might not be up yet, try again later. - RLOGE("Ipv6Monitor could not initialize %s yet, retrying later", - mInterfaceName.c_str()); - mPollTimeout = kDeferredTimeoutMilliseconds; - return InitResult::Deferred; - } - RLOGE("Ipv6Monitor failed to get interface flags for %s: %s", - mInterfaceName.c_str(), strerror(errno)); - return InitResult::Error; - } - - if ((request.ifr_flags & IFF_ALLMULTI) == 0) { - // The flag is not set, we have to make another call - request.ifr_flags |= IFF_ALLMULTI; - - status = ::ioctl(mSocketFd, SIOCSIFFLAGS, &request); - if (status != 0) { - RLOGE("Ipv6Monitor failed to set interface flags for %s: %s", - mInterfaceName.c_str(), strerror(errno)); - return InitResult::Error; - } - } - - // Add a BPF filter to the socket so that we only receive the specific - // type of packet we're interested in. Otherwise we will receive ALL - // traffic on this interface. - struct sock_fprog filter; - filter.len = kNdpFilterSize; - // The API doesn't have const but it's not going to modify it so this is OK - filter.filter = const_cast<struct sock_filter*>(kNdpFilter); - status = ::setsockopt(mSocketFd, - SOL_SOCKET, - SO_ATTACH_FILTER, - &filter, - sizeof(filter)); - if (status != 0) { - RLOGE("Ipv6Monitor failed to set socket filter: %s", strerror(errno)); - return InitResult::Error; - } - - // Get the hardware address of the interface into a sockaddr struct for bind - struct sockaddr_ll ethAddr; - memset(ðAddr, 0, sizeof(ethAddr)); - ethAddr.sll_family = AF_PACKET; - ethAddr.sll_protocol = htons(ETH_P_IPV6); - ethAddr.sll_ifindex = if_nametoindex(mInterfaceName.c_str()); - if (ethAddr.sll_ifindex == 0) { - RLOGE("Ipv6Monitor failed to find index for %s: %s", - mInterfaceName.c_str(), strerror(errno)); - return InitResult::Error; - } - - status = ::ioctl(mSocketFd, SIOCGIFHWADDR, &request); - if (status != 0) { - RLOGE("Ipv6Monitor failed to get hardware address for %s: %s", - mInterfaceName.c_str(), strerror(errno)); - return InitResult::Error; - } - memcpy(ethAddr.sll_addr, request.ifr_addr.sa_data, ETH_ALEN); - - // Now bind to the hardware address - status = ::bind(mSocketFd, - reinterpret_cast<const struct sockaddr*>(ðAddr), - sizeof(ethAddr)); - if (status != 0) { - RLOGE("Ipv6Monitor failed to bind to %s hardware address: %s", - mInterfaceName.c_str(), strerror(errno)); - return InitResult::Error; - } - mFullyInitialized = true; - return InitResult::Success; -} - -void Ipv6Monitor::runAsync() { - std::unique_lock<std::mutex> lock(mThreadMutex); - mThread = std::make_unique<std::thread>([this]() { run(); }); -} - -void Ipv6Monitor::stop() { - std::unique_lock<std::mutex> lock(mThreadMutex); - if (!mThread) { - return; - } - ::write(mControlSocket[kControlClient], &kMonitorStopCommand, 1); - char ack = -1; - while (ack != kMonitorAckCommand) { - ::read(mControlSocket[kControlClient], &ack, sizeof(ack)); - } - mThread->join(); - mThread.reset(); -} - -void Ipv6Monitor::run() { - std::array<struct pollfd, 2> fds; - fds[0].events = POLLIN; - fds[0].fd = mControlSocket[kControlServer]; - fds[1].events = POLLIN; - fds[1].fd = mSocketFd; - - bool running = true; - while (running) { - int status = ::poll(fds.data(), fds.size(), mPollTimeout); - if (status < 0) { - if (errno == EINTR) { - // Interrupted, keep going - continue; - } - // An error occurred - RLOGE("Ipv6Monitor fatal failure polling failed; %s", - strerror(errno)); - break; - } else if (status == 0) { - // Timeout, nothing to read - if (!mFullyInitialized) { - InitResult result = initInterfaces(); - switch (result) { - case InitResult::Error: - // Something went wrong this time and we can't recover - running = false; - break; - case InitResult::Deferred: - // We need to keep waiting and then try again - mPollTimeout = kDeferredTimeoutMilliseconds; - break; - case InitResult::Success: - // Interfaces are initialized, no need to timeout again - mPollTimeout = -1; - break; - } - } - continue; - } - - if (fds[0].revents & POLLIN) { - // Control message received - char command = -1; - if (::read(mControlSocket[kControlServer], - &command, - sizeof(command)) == 1) { - if (command == kMonitorStopCommand) { - break; - } - } - } else if (fds[1].revents & POLLIN) { - onReadAvailable(); - } - } - ::write(mControlSocket[kControlServer], &kMonitorAckCommand, 1); -} - -void Ipv6Monitor::onReadAvailable() { - char buffer[kReadBufferSize]; - - ssize_t bytesRead = 0; - while (true) { - bytesRead = ::recv(mSocketFd, buffer, sizeof(buffer), 0); - if (bytesRead < 0) { - if (errno == EINTR) { - // Interrupted, try again right away - continue; - } - if (errno != EAGAIN && errno != EWOULDBLOCK) { - // Do not report an error for the above error codes, they are - // part of the normal turn of events. We just need to try again - // later when we run into those errors. - RLOGE("Ipv6Monitor failed to receive data: %s", - strerror(errno)); - } - return; - } - break; - } - - if (mMonitorCallback == nullptr) { - // No point in doing anything, we have read the data so the socket - // buffer doesn't fill up and that's all we can do. - return; - } - - if (static_cast<size_t>(bytesRead) < sizeof(ip6_hdr) + sizeof(icmp6_hdr)) { - // This message cannot be an ICMPv6 packet, ignore it - return; - } - - auto ipv6 = reinterpret_cast<const ip6_hdr*>(buffer); - uint8_t version = (ipv6->ip6_vfc & 0xF0) >> 4; - if (version != 6 || ipv6->ip6_nxt != IPPROTO_ICMPV6) { - // This message is not an IPv6 packet or not an ICMPv6 packet, ignore it - return; - } - - // The ICMP header starts right after the IPv6 header - auto icmp = reinterpret_cast<const icmp6_hdr*>(buffer + sizeof(ip6_hdr)); - if (icmp->icmp6_code != 0) { - // All packets we care about have an icmp code of zero. - return; - } - - if (icmp->icmp6_type != ND_ROUTER_ADVERT) { - // We only care about router advertisements - return; - } - - // At this point we know it's a valid packet, let's look inside - - // The gateway is the same as the source in the IP header - in6_addr gateway = ipv6->ip6_src; - - // Search through the options for DNS servers - const char* options = buffer + sizeof(ip6_hdr) + sizeof(nd_router_advert); - const nd_opt_hdr* option = reinterpret_cast<const nd_opt_hdr*>(options); - - std::vector<in6_addr> dnsServers; - const nd_opt_hdr* nextOpt = nullptr; - for (const nd_opt_hdr* opt = option; opt; opt = nextOpt) { - auto nextOptLoc = - reinterpret_cast<const char*>(opt) + opt->nd_opt_len * 8u; - if (nextOptLoc > buffer + bytesRead) { - // Not enough room for this option, abort - break; - } - if (nextOptLoc < buffer + bytesRead) { - nextOpt = reinterpret_cast<const nd_opt_hdr*>(nextOptLoc); - } else { - nextOpt = nullptr; - } - if (opt->nd_opt_type != 25 || opt->nd_opt_len < 1) { - // Not an RNDSS option, skip it - continue; - } - - size_t numEntries = (opt->nd_opt_len - 1) / 2; - const char* addrLoc = reinterpret_cast<const char*>(opt); - addrLoc += kRecursiveDnsOptHeaderSize; - auto addrs = reinterpret_cast<const in6_addr*>(addrLoc); - - for (size_t i = 0; i < numEntries; ++i) { - dnsServers.push_back(addrs[i]); - } - } - - bool changed = false; - if (gateway != mGateway) { - changed = true; - mGateway = gateway; - } - - for (const auto& dns : dnsServers) { - if (mDnsServers.find(dns) == mDnsServers.end()) { - mDnsServers.insert(dns); - changed = true; - } - } - - if (changed) { - mMonitorCallback(&gateway, dnsServers.data(), dnsServers.size()); - } -} - -extern "C" -struct ipv6Monitor* ipv6MonitorCreate(const char* interfaceName) { - auto monitor = std::make_unique<Ipv6Monitor>(interfaceName); - if (!monitor || monitor->init() == Ipv6Monitor::InitResult::Error) { - return nullptr; - } - return reinterpret_cast<struct ipv6Monitor*>(monitor.release()); -} - -extern "C" -void ipv6MonitorFree(struct ipv6Monitor* ipv6Monitor) { - auto monitor = reinterpret_cast<Ipv6Monitor*>(ipv6Monitor); - delete monitor; -} - -extern "C" -void ipv6MonitorSetCallback(struct ipv6Monitor* ipv6Monitor, - ipv6MonitorCallback callback) { - auto monitor = reinterpret_cast<Ipv6Monitor*>(ipv6Monitor); - monitor->setCallback(callback); -} - -extern "C" -void ipv6MonitorRunAsync(struct ipv6Monitor* ipv6Monitor) { - auto monitor = reinterpret_cast<Ipv6Monitor*>(ipv6Monitor); - monitor->runAsync(); -} - -extern "C" -void ipv6MonitorStop(struct ipv6Monitor* ipv6Monitor) { - auto monitor = reinterpret_cast<Ipv6Monitor*>(ipv6Monitor); - monitor->stop(); -} - diff --git a/ril/ipv6_monitor.h b/ril/ipv6_monitor.h deleted file mode 100644 index b58402dd..00000000 --- a/ril/ipv6_monitor.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <netinet/in.h> - -#ifdef __cplusplus -extern "C" { -#endif - -struct ipv6Monitor; - -// A callback for when the IPv6 configuration changes. -typedef void (*ipv6MonitorCallback)(const struct in6_addr* /*gateway*/, - const struct in6_addr* /*dns servers*/, - size_t /*number of dns servers */); - -// Create an IPv6 monitor that will monitor |interfaceName| for IPv6 router -// advertisements. The monitor will trigger a callback if the gateway and/or -// DNS servers provided by router advertisements change at any point. -struct ipv6Monitor* ipv6MonitorCreate(const char* interfaceName); -void ipv6MonitorFree(struct ipv6Monitor* monitor); - -void ipv6MonitorSetCallback(struct ipv6Monitor* monitor, - ipv6MonitorCallback callback); -void ipv6MonitorRunAsync(struct ipv6Monitor* monitor); -void ipv6MonitorStop(struct ipv6Monitor* monitor); - -#ifdef __cplusplus -} // extern "C" -#endif - - diff --git a/ril/reference-ril.c b/ril/reference-ril.c index 85662312..48ad12cb 100644 --- a/ril/reference-ril.c +++ b/ril/reference-ril.c @@ -45,17 +45,11 @@ #include <netinet/in.h> #include "if_monitor.h" -#include "ipv6_monitor.h" #include "ril.h" #define LOG_TAG "RIL" #include <utils/Log.h> -#define MAX(x, y) ({\ - __typeof__(x) _x = (x); \ - __typeof__(y) _y = (y); \ - _x > _y ? _x : _y; }) - static void *noopRemoveWarning( void *a ) { return a; } #define RIL_UNUSED_PARM(a) noopRemoveWarning((void *)&(a)); @@ -279,13 +273,9 @@ static int s_mnc = 0; static int s_lac = 0; static int s_cid = 0; -// A string containing all IP addresses of the radio interface -static char s_if_addresses[8192]; -// A string containing the IPv6 gateway of the radio interface -static char s_ipv6_gateway[INET6_ADDRSTRLEN]; -// A string containing the IPv6 DNS servers of the radio interface -static char s_ipv6_dns[8192]; -static pthread_mutex_t s_addresses_mutex = PTHREAD_MUTEX_INITIALIZER; +// A string containing all the IPv6 addresses of the radio interface +static char s_ipv6_addresses[8192]; +static pthread_mutex_t s_ipv6_addresses_mutex = PTHREAD_MUTEX_INITIALIZER; static void pollSIMState (void *param); static void setRadioState(RIL_RadioState newState); @@ -628,8 +618,6 @@ static void requestOrSendDataCallList(RIL_Token *t) char propValue[PROP_VALUE_MAX]; bool hasWifi = hasWifiCapability(); const char* radioInterfaceName = getRadioInterfaceName(hasWifi); - char ipv6Gateway[INET6_ADDRSTRLEN]; - char ipv6Dns[8192]; err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response); if (err != 0 || p_response->success == 0) { @@ -747,23 +735,24 @@ static void requestOrSendDataCallList(RIL_Token *t) if (err < 0) goto error; - pthread_mutex_lock(&s_addresses_mutex); + pthread_mutex_lock(&s_ipv6_addresses_mutex); - // Extra space for null terminator - int addresses_size = MAX(strlen(out), strlen(s_if_addresses)) + 1; + // Extra space for null terminator and separating space + int addresses_size = strlen(out) + strlen(s_ipv6_addresses) + 2; responses[i].addresses = alloca(addresses_size); - if (*s_if_addresses) { - // Interface addresses exist, use them. - strlcpy(responses[i].addresses, s_if_addresses, addresses_size); + if (*s_ipv6_addresses) { + // IPv6 addresses exist, add them + snprintf(responses[i].addresses, addresses_size, + "%s %s", + hasWifi ? RADIO0_IPV4_ADDRESS : out, + s_ipv6_addresses); } else { - // No known interface address, use whatever the modem provided - strlcpy(responses[i].addresses, out, addresses_size); + // Only provide the IPv4 address + strlcpy(responses[i].addresses, + hasWifi ? RADIO0_IPV4_ADDRESS : out, + addresses_size); } - - strlcpy(ipv6Gateway, s_ipv6_gateway, sizeof(ipv6Gateway)); - strlcpy(ipv6Dns, s_ipv6_dns, sizeof(ipv6Dns)); - - pthread_mutex_unlock(&s_addresses_mutex); + pthread_mutex_unlock(&s_ipv6_addresses_mutex); if (isInEmulator()) { /* We are in the emulator - the dns servers are listed @@ -780,15 +769,12 @@ static void requestOrSendDataCallList(RIL_Token *t) int nn; char propName[PROP_NAME_MAX]; char propValue[PROP_VALUE_MAX]; - char* gateways = NULL; - size_t gatewaysSize = 0; dnslist[0] = 0; for (nn = 1; nn <= 4; nn++) { /* Probe net.eth0.dns<n> */ - snprintf(propName, sizeof propName, "net.%s.dns%d", - radioInterfaceName, nn); + snprintf(propName, sizeof propName, "net.eth0.dns%d", nn); /* Ignore if undefined */ if (property_get(propName, propValue, "") <= 0) { @@ -802,8 +788,7 @@ static void requestOrSendDataCallList(RIL_Token *t) } for (nn = 1; nn <= 4; ++nn) { /* Probe net.eth0.ipv6dns<n> for IPv6 DNS servers */ - snprintf(propName, sizeof propName, "net.%s.ipv6dns%d", - radioInterfaceName, nn); + snprintf(propName, sizeof propName, "net.eth0.ipv6dns%d", nn); /* Ignore if undefined */ if (property_get(propName, propValue, "") <= 0) { continue; @@ -815,31 +800,13 @@ static void requestOrSendDataCallList(RIL_Token *t) responses[i].dnses = dnslist; - /* There is only one gateway in the emulator. */ - snprintf(propName, sizeof propName, "net.%s.gw", - radioInterfaceName); - - gatewaysSize = strlen(ipv6Gateway); - if (property_get(propName, propValue, "") > 0) { - if (gatewaysSize > 0) { - // Room for a separating space - ++gatewaysSize; - } - gatewaysSize += strlen(propValue); - } - if (gatewaysSize > 0) { - // Room for a terminating null byte - ++gatewaysSize; - responses[i].gateways = alloca(gatewaysSize); - if (ipv6Gateway[0]) { - strlcpy(responses[i].gateways, ipv6Gateway, gatewaysSize); - } - if (propValue[0]) { - if (responses[i].gateways[0] != '\0') { - strlcat(responses[i].gateways, " ", gatewaysSize); - } - strlcat(responses[i].gateways, propValue, gatewaysSize); - } + /* There is only one gateway in the emulator. If WiFi is + * configured the interface visible to RIL will be behind a NAT + * where the gateway is different. */ + if (hasWifi) { + responses[i].gateways = "192.168.200.1"; + } else if (property_get("net.eth0.gw", propValue, "") > 0) { + responses[i].gateways = propValue; } else { responses[i].gateways = ""; } @@ -856,14 +823,13 @@ static void requestOrSendDataCallList(RIL_Token *t) at_response_free(p_response); - if (t != NULL) { + if (t != NULL) RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses, n * sizeof(RIL_Data_Call_Response_v11)); - } else { + else RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED, responses, n * sizeof(RIL_Data_Call_Response_v11)); - } return; @@ -3984,18 +3950,22 @@ static void onInterfaceAddressChange(unsigned int ifIndex, return; } - pthread_mutex_lock(&s_addresses_mutex); + pthread_mutex_lock(&s_ipv6_addresses_mutex); // Clear out any existing addresses, we receive a full set of addresses // that are going to replace the existing ones. - s_if_addresses[0] = '\0'; - currentLoc = s_if_addresses; - remaining = sizeof(s_if_addresses); + s_ipv6_addresses[0] = '\0'; + currentLoc = s_ipv6_addresses; + remaining = sizeof(s_ipv6_addresses); for (i = 0; i < numAddresses; ++i) { + if (addresses[i].family != AF_INET6) { + // Only care about IPv6 addresses + continue; + } char address[INET6_ADDRSTRLEN]; if (inet_ntop(addresses[i].family, &addresses[i].addr, address, sizeof(address))) { int printed = 0; - if (s_if_addresses[0]) { + if (s_ipv6_addresses[0]) { // We've already printed something, separate them if (remaining < 1) { continue; @@ -4013,38 +3983,7 @@ static void onInterfaceAddressChange(unsigned int ifIndex, RLOGE("Unable to convert address to string for if %s", ifName); } } - pthread_mutex_unlock(&s_addresses_mutex); - - // Send unsolicited call list change to notify upper layers about the new - // addresses - requestOrSendDataCallList(NULL); -} - -static void onIpv6Change(const struct in6_addr* gateway, - const struct in6_addr* dnsServers, - size_t numDnsServers) { - char* dnsLoc = s_ipv6_dns; - size_t remaining = sizeof(s_ipv6_dns); - char address[INET6_ADDRSTRLEN]; - - pthread_mutex_lock(&s_addresses_mutex); - - inet_ntop(AF_INET6, gateway, s_ipv6_gateway, sizeof(s_ipv6_gateway)); - - s_ipv6_dns[0] = '\0'; - for (size_t i = 0; i < numDnsServers; ++i) { - if (inet_ntop(AF_INET6, &dnsServers[i], address, sizeof(address))) { - size_t len = strlcat(s_ipv6_dns, address, sizeof(s_ipv6_dns)); - if (i + 1 < numDnsServers && len + 1 < sizeof(s_ipv6_dns)) { - // There's more to come and there's room for more, separate - // multiple DNS servers by a space. - s_ipv6_dns[len] = ' '; - s_ipv6_dns[len + 1] = '\0'; - } - } - } - - pthread_mutex_unlock(&s_addresses_mutex); + pthread_mutex_unlock(&s_ipv6_addresses_mutex); // Send unsolicited call list change to notify upper layers about the new // addresses @@ -4056,20 +3995,14 @@ mainLoop(void *param __unused) { int fd; int ret; - bool hasWifi = hasWifiCapability(); - const char* radioInterfaceName = getRadioInterfaceName(hasWifi); - struct ifMonitor* ifMonitor = ifMonitorCreate(); - struct ipv6Monitor* ipv6Monitor = ipv6MonitorCreate(radioInterfaceName); + struct ifMonitor* monitor = ifMonitorCreate(); AT_DUMP("== ", "entering mainLoop()", -1 ); at_set_on_reader_closed(onATReaderClosed); at_set_on_timeout(onATTimeout); - ifMonitorSetCallback(ifMonitor, &onInterfaceAddressChange); - ifMonitorRunAsync(ifMonitor); - - ipv6MonitorSetCallback(ipv6Monitor, &onIpv6Change); - ipv6MonitorRunAsync(ipv6Monitor); + ifMonitorSetCallback(monitor, &onInterfaceAddressChange); + ifMonitorRunAsync(monitor); for (;;) { fd = -1; @@ -4119,11 +4052,8 @@ mainLoop(void *param __unused) RLOGI("Re-opening after close"); } - ifMonitorStop(ifMonitor); - ifMonitorFree(ifMonitor); - - ipv6MonitorStop(ipv6Monitor); - ipv6MonitorFree(ipv6Monitor); + ifMonitorStop(monitor); + ifMonitorFree(monitor); return NULL; } diff --git a/sepolicy/common/OWNERS b/sepolicy/common/OWNERS index e6fbbd47..ff296774 100644 --- a/sepolicy/common/OWNERS +++ b/sepolicy/common/OWNERS @@ -3,7 +3,6 @@ bowgotsai@google.com jbires@google.com jeffv@google.com jgalenson@google.com -nnk@google.com sspatil@google.com tomcherry@google.com trong@google.com diff --git a/sepolicy/common/bootanim.te b/sepolicy/common/bootanim.te index 4d011e10..bc84ee73 100644 --- a/sepolicy/common/bootanim.te +++ b/sepolicy/common/bootanim.te @@ -4,7 +4,6 @@ allow bootanim ashmem_device:chr_file execute; dontaudit bootanim system_data_file:dir read; allow bootanim graphics_device:chr_file { read ioctl open }; -allow bootanim gpu_device:chr_file { read ioctl open }; typeattribute bootanim system_writes_vendor_properties_violators; set_prop(bootanim, qemu_prop) diff --git a/sepolicy/common/bug_map b/sepolicy/common/bug_map deleted file mode 100644 index 839b49e6..00000000 --- a/sepolicy/common/bug_map +++ /dev/null @@ -1,17 +0,0 @@ -hal_wifi_default default_prop file b/131598173 -hal_wifi_default vendor_default_prop property_service b/131598173 -init unlabeled dir b/131596633 -init vendor_toolbox_exec file b/132695863 -installd device file b/131595213 -kernel kernel system b/131597442 -netd device file b/131598170 -platform_app vendor_default_prop file b/130684647 -priv_app property_socket sock_file b/131598844 -priv_app varrun_file dir b/131598844 -storaged device file b/131598843 -toolbox unlabeled dir b/131599097 -toolbox toolbox capability b/131599097 -ueventd metadata_file dir b/131594529 -vendor_init exported2_default_prop property_service b/131601458 -init serial_device chr_file b/134145307 -gsid device file b/133324244 diff --git a/sepolicy/common/dhcpclient.te b/sepolicy/common/dhcpclient.te index cff44712..f1ba3f02 100644 --- a/sepolicy/common/dhcpclient.te +++ b/sepolicy/common/dhcpclient.te @@ -8,14 +8,14 @@ net_domain(dhcpclient) allow dhcpclient execns:fd use; set_prop(dhcpclient, net_eth0_prop); -set_prop(dhcpclient, net_radio0_prop); dontaudit dhcpclient kernel:system module_request; allow dhcpclient self:capability { net_admin net_raw }; -allow dhcpclient self:netlink_route_socket { ioctl write nlmsg_write }; +allow dhcpclient self:udp_socket create; +allow dhcpclient self:netlink_route_socket { write nlmsg_write }; allow dhcpclient varrun_file:dir search; allow dhcpclient self:packet_socket { create bind write read }; -allowxperm dhcpclient self:netlink_route_socket ioctl { SIOCGIFFLAGS - SIOCSIFFLAGS - SIOCSIFMTU - SIOCGIFINDEX - SIOCGIFHWADDR }; +allowxperm dhcpclient self:udp_socket ioctl { SIOCSIFFLAGS + SIOCSIFADDR + SIOCSIFNETMASK + SIOCSIFMTU + SIOCGIFHWADDR }; diff --git a/sepolicy/common/dhcprelay.te b/sepolicy/common/dhcprelay.te deleted file mode 100644 index 4c4ffdf5..00000000 --- a/sepolicy/common/dhcprelay.te +++ /dev/null @@ -1,21 +0,0 @@ -# DHCP relay -type dhcprelay, domain; -type dhcprelay_exec, exec_type, vendor_file_type, file_type; - -init_daemon_domain(dhcprelay) -net_domain(dhcprelay) - -allow dhcprelay execns:fd use; - -set_prop(dhcprelay, net_eth0_prop); -dontaudit dhcprelay kernel:system module_request; -allow dhcprelay self:capability { net_admin net_bind_service net_raw }; -allow dhcprelay self:udp_socket create; -allow dhcprelay self:netlink_route_socket { write nlmsg_write }; -allow dhcprelay varrun_file:dir search; -allow dhcprelay self:packet_socket { create bind write read }; -allowxperm dhcprelay self:udp_socket ioctl { SIOCSIFFLAGS - SIOCSIFADDR - SIOCSIFNETMASK - SIOCSIFMTU - SIOCGIFHWADDR }; diff --git a/sepolicy/common/dhcpserver.te b/sepolicy/common/dhcpserver.te new file mode 100644 index 00000000..7e8ba263 --- /dev/null +++ b/sepolicy/common/dhcpserver.te @@ -0,0 +1,12 @@ +# DHCP server +type dhcpserver, domain; +type dhcpserver_exec, exec_type, vendor_file_type, file_type; + +init_daemon_domain(dhcpserver) +net_domain(dhcpserver) + +allow dhcpserver execns:fd use; + +get_prop(dhcpserver, net_eth0_prop); +allow dhcpserver self:udp_socket { ioctl create setopt bind }; +allow dhcpserver self:capability { net_raw net_bind_service }; diff --git a/sepolicy/common/execns.te b/sepolicy/common/execns.te index 265fb835..24eee410 100644 --- a/sepolicy/common/execns.te +++ b/sepolicy/common/execns.te @@ -15,6 +15,9 @@ domain_auto_trans(init, execns_exec, execns); # Allow dhcpclient to be run by execns in its own domain domain_auto_trans(execns, dhcpclient_exec, dhcpclient); +# Allow dhcpserver to be run by execns in its own domain +domain_auto_trans(execns, dhcpserver_exec, dhcpserver); + # Allow hostapd_nohidl to be run by execns in its own domain domain_auto_trans(execns, hostapd_nohidl_exec, hostapd_nohidl); diff --git a/sepolicy/common/file_contexts b/sepolicy/common/file_contexts index 6bcc6732..c1350f94 100644 --- a/sepolicy/common/file_contexts +++ b/sepolicy/common/file_contexts @@ -15,9 +15,6 @@ /dev/goldfish_sync u:object_r:qemu_device:s0 /dev/goldfish_address_space u:object_r:qemu_device:s0 /dev/qemu_.* u:object_r:qemu_device:s0 -/dev/dri/card0 u:object_r:gpu_device:s0 -/dev/dri/controlD64 u:object_r:gpu_device:s0 -/dev/dri/renderD128 u:object_r:gpu_device:s0 /dev/ttyGF[0-9]* u:object_r:serial_device:s0 /dev/ttyS2 u:object_r:console_device:s0 /vendor/bin/init\.ranchu-core\.sh u:object_r:goldfish_setup_exec:s0 @@ -26,17 +23,16 @@ /vendor/bin/qemu-props u:object_r:qemu_props_exec:s0 /vendor/bin/createns u:object_r:createns_exec:s0 /vendor/bin/execns u:object_r:execns_exec:s0 -/vendor/bin/ip u:object_r:goldfish_ip_exec:s0 +/vendor/bin/ipv6proxy u:object_r:ipv6proxy_exec:s0 /vendor/bin/iw u:object_r:goldfish_iw_exec:s0 /vendor/bin/dhcpclient u:object_r:dhcpclient_exec:s0 +/vendor/bin/dhcpserver u:object_r:dhcpserver_exec:s0 /vendor/bin/hostapd_nohidl u:object_r:hostapd_nohidl_exec:s0 /vendor/bin/netmgr u:object_r:netmgr_exec:s0 -/vendor/bin/wifi_forwarder u:object_r:wifi_forwarder_exec:s0 /vendor/bin/hw/android\.hardware\.drm@1\.0-service\.widevine u:object_r:hal_drm_widevine_exec:s0 /vendor/bin/hw/android\.hardware\.drm@1\.2-service\.widevine u:object_r:hal_drm_widevine_exec:s0 /vendor/bin/hw/android\.hardware\.drm@1\.2-service\.clearkey u:object_r:hal_drm_clearkey_exec:s0 -/vendor/bin/hw/android\.hardware\.gatekeeper@1\.0-service.software u:object_r:hal_gatekeeper_default_exec:s0 /vendor/bin/hw/android\.hardware\.keymaster@4\.0-strongbox-service u:object_r:hal_keymaster_default_exec:s0 /vendor/bin/hw/android\.hardware\.health@2\.0-service.goldfish u:object_r:hal_health_default_exec:s0 /vendor/bin/hw/android\.hardware\.power@1\.1-service.ranchu u:object_r:hal_power_default_exec:s0 @@ -57,8 +53,6 @@ /vendor/lib(64)?/libGLESv1_enc\.so u:object_r:same_process_hal_file:s0 /vendor/lib(64)?/libGLESv2_enc\.so u:object_r:same_process_hal_file:s0 /vendor/lib(64)?/libvulkan_enc\.so u:object_r:same_process_hal_file:s0 -/vendor/lib(64)?/libandroidemu\.so u:object_r:same_process_hal_file:s0 -/vendor/lib(64)?/libdrm.so u:object_r:same_process_hal_file:s0 # data /data/vendor/mediadrm(/.*)? u:object_r:mediadrm_vendor_data_file:s0 diff --git a/sepolicy/common/goldfish_ip.te b/sepolicy/common/goldfish_ip.te deleted file mode 100644 index c914596a..00000000 --- a/sepolicy/common/goldfish_ip.te +++ /dev/null @@ -1,5 +0,0 @@ -type goldfish_ip, domain; -type goldfish_ip_exec, exec_type, vendor_file_type, file_type; - -init_daemon_domain(goldfish_ip) -net_domain(goldfish_ip) diff --git a/sepolicy/common/goldfish_setup.te b/sepolicy/common/goldfish_setup.te index e3071f75..187d0558 100644 --- a/sepolicy/common/goldfish_setup.te +++ b/sepolicy/common/goldfish_setup.te @@ -14,7 +14,6 @@ allowxperm goldfish_setup self:udp_socket ioctl priv_sock_ioctls; wakelock_use(goldfish_setup); allow goldfish_setup vendor_shell_exec:file { rx_file_perms }; #============= goldfish_setup ============== -allow goldfish_setup goldfish_ip_exec:file execute_no_trans; allow goldfish_setup goldfish_iw_exec:file execute_no_trans; # Set system properties to start services @@ -34,6 +33,10 @@ allow goldfish_setup system_data_file:dir getattr; allow goldfish_setup kernel:system module_request; set_prop(goldfish_setup, qemu_prop); get_prop(goldfish_setup, net_share_prop); +# Allow goldfish_setup to run /system/bin/ip and /system/bin/iw +# TODO(b/113124961): clean up this Treble violation. +typeattribute goldfish_setup vendor_executes_system_violators; +allow goldfish_setup system_file:file rx_file_perms; # Allow goldfish_setup to run init.wifi.sh allow goldfish_setup goldfish_setup_exec:file execute_no_trans; #Allow goldfish_setup to run createns in its own domain @@ -49,5 +52,4 @@ allow goldfish_setup createns:lnk_file { read }; # Allow goldfish_setup to copy the hostapd conf template to the vendor data dir allow goldfish_setup hostapd_data_file:file create_file_perms; allow goldfish_setup hostapd_data_file:dir rw_dir_perms; -#allow goldfish_setup system_file:file { execute getattr open read }; -dontaudit goldfish_setup self:capability dac_override; +allow goldfish_setup system_file:file { execute getattr open read }; diff --git a/sepolicy/common/hal_drm_clearkey.te b/sepolicy/common/hal_drm_clearkey.te index 5632c3b2..976b9fab 100644 --- a/sepolicy/common/hal_drm_clearkey.te +++ b/sepolicy/common/hal_drm_clearkey.te @@ -7,3 +7,5 @@ init_daemon_domain(hal_drm_clearkey) hal_server_domain(hal_drm_clearkey, hal_drm) vndbinder_use(hal_drm_clearkey); + +allow hal_drm_clearkey { appdomain -isolated_app }:fd use; diff --git a/sepolicy/common/hal_drm_widevine.te b/sepolicy/common/hal_drm_widevine.te index 8478ee83..81984109 100644 --- a/sepolicy/common/hal_drm_widevine.te +++ b/sepolicy/common/hal_drm_widevine.te @@ -6,6 +6,7 @@ type hal_drm_widevine_exec, exec_type, vendor_file_type, file_type; init_daemon_domain(hal_drm_widevine) allow hal_drm mediacodec:fd use; +allow hal_drm { appdomain -isolated_app }:fd use; vndbinder_use(hal_drm_widevine); hal_client_domain(hal_drm_widevine, hal_graphics_composer); diff --git a/sepolicy/common/hal_graphics_allocator_default.te b/sepolicy/common/hal_graphics_allocator_default.te index 527cabdb..c57e4522 100644 --- a/sepolicy/common/hal_graphics_allocator_default.te +++ b/sepolicy/common/hal_graphics_allocator_default.te @@ -1,6 +1,4 @@ allow hal_graphics_allocator_default graphics_device:dir search; -allow hal_graphics_allocator_default graphics_device:chr_file { ioctl open read write map rw_file_perms }; -allow hal_graphics_allocator_default gpu_device:dir search; -allow hal_graphics_allocator_default gpu_device:chr_file { ioctl open read write map rw_file_perms }; +allow hal_graphics_allocator_default graphics_device:chr_file { ioctl open read write }; allow hal_graphics_allocator_default dumpstate:fd use; allow hal_graphics_allocator_default dumpstate:fifo_file write; diff --git a/sepolicy/common/hal_graphics_composer_default.te b/sepolicy/common/hal_graphics_composer_default.te index 3b0c862f..e9205cda 100644 --- a/sepolicy/common/hal_graphics_composer_default.te +++ b/sepolicy/common/hal_graphics_composer_default.te @@ -1,4 +1,3 @@ #============= hal_graphics_composer_default ============== allow hal_graphics_composer_default vndbinder_device:chr_file { ioctl open read write map }; -allow hal_graphics_composer_default graphics_device:chr_file { ioctl open read write map }; -allow hal_graphics_composer_default gpu_device:chr_file { ioctl open read write map }; + diff --git a/sepolicy/common/ipv6proxy.te b/sepolicy/common/ipv6proxy.te new file mode 100644 index 00000000..a6315016 --- /dev/null +++ b/sepolicy/common/ipv6proxy.te @@ -0,0 +1,18 @@ +# IPv6 proxying +type ipv6proxy, domain; +type ipv6proxy_exec, exec_type, vendor_file_type, file_type; + +init_daemon_domain(ipv6proxy) +net_domain(ipv6proxy) + +# Allow ipv6proxy to be run by execns in its own domain +domain_auto_trans(execns, ipv6proxy_exec, ipv6proxy); +allow ipv6proxy execns:fd use; + +set_prop(ipv6proxy, net_eth0_prop); +dontaudit ipv6proxy kernel:system module_request; +allow ipv6proxy self:capability { sys_admin sys_module net_admin net_raw }; +allow ipv6proxy self:packet_socket { bind create read }; +allow ipv6proxy self:netlink_route_socket nlmsg_write; +allow ipv6proxy varrun_file:dir search; +allowxperm ipv6proxy self:udp_socket ioctl { SIOCSIFFLAGS SIOCGIFHWADDR }; diff --git a/sepolicy/common/mediacodec.te b/sepolicy/common/mediacodec.te index 41241a3f..acf4e59b 100644 --- a/sepolicy/common/mediacodec.te +++ b/sepolicy/common/mediacodec.te @@ -1,4 +1 @@ allow mediacodec system_file:dir { open read }; -allow mediacodec vendor_data_file:dir search; -allow mediacodec vendor_data_file:file { open read getattr }; -allow mediacodec vendor_data_file:lnk_file read; diff --git a/sepolicy/common/netmgr.te b/sepolicy/common/netmgr.te index c7abcb92..96caf82f 100644 --- a/sepolicy/common/netmgr.te +++ b/sepolicy/common/netmgr.te @@ -7,31 +7,25 @@ net_domain(netmgr) allow netmgr execns:fd use; -# Set property to indicate bridging is complete -set_prop(netmgr, vendor_net); # Set ctrl.restart property to restart hostapd when config changes set_prop(netmgr, ctl_default_prop); # Modify hostapd config file -allow netmgr hostapd_data_file:file create_file_perms; +allow netmgr hostapd_data_file:file rw_file_perms; allow netmgr hostapd_data_file:dir rw_dir_perms; # Assign addresses to new interfaces as hostapd brings them up allow netmgr self:capability { net_raw net_admin }; -allow netmgr self:socket { create }; -allow netmgr self:unix_dgram_socket ioctl; -allow netmgr self:packet_socket { ioctl getopt map }; +allow netmgr self:socket { create ioctl }; +allow netmgr self:packet_socket { ioctl getopt }; allow netmgr self:udp_socket { ioctl }; allow netmgr proc_net:file { read getattr open }; -allowxperm netmgr self:unix_dgram_socket ioctl { SIOCETHTOOL }; -allowxperm netmgr self:udp_socket ioctl { SIOCSIFFLAGS - SIOCBRADDBR - SIOCBRADDIF - SIOCBRDELIF }; +allowxperm netmgr self:socket ioctl { SIOCETHTOOL }; +allowxperm netmgr self:udp_socket ioctl { SIOCSIFADDR SIOCSIFNETMASK SIOCSIFBRDADDR }; allowxperm netmgr self:packet_socket ioctl { SIOCGIFINDEX SIOCGIFHWADDR }; -# Allow netmgr to run ip and modify route table to block unblock traffic -allow netmgr goldfish_ip_exec:file execute_no_trans; -allow netmgr self:netlink_route_socket nlmsg_write; +# Allow netmgr to run iptables to block and unblock network traffic +# TODO(b/113124961): clean up this Treble violation. +typeattribute netmgr vendor_executes_system_violators; +allow netmgr system_file:file execute_no_trans; +allow netmgr system_file:file lock; # Packet socket for wifi forwarding allow netmgr self:packet_socket { bind create read setopt write }; -allow netmgr kernel:system module_request; -allow netmgr self:capability sys_module; diff --git a/sepolicy/common/property.te b/sepolicy/common/property.te index 40461057..3593a39d 100644 --- a/sepolicy/common/property.te +++ b/sepolicy/common/property.te @@ -2,6 +2,4 @@ type qemu_prop, property_type; type qemu_cmdline, property_type; type radio_noril_prop, property_type; type net_eth0_prop, property_type; -type net_radio0_prop, property_type; type net_share_prop, property_type; -type vendor_net, property_type; diff --git a/sepolicy/common/property_contexts b/sepolicy/common/property_contexts index 86f01149..4a82974f 100644 --- a/sepolicy/common/property_contexts +++ b/sepolicy/common/property_contexts @@ -1,11 +1,9 @@ qemu. u:object_r:qemu_prop:s0 qemu.cmdline u:object_r:qemu_cmdline:s0 vendor.qemu u:object_r:qemu_prop:s0 -vendor.network u:object_r:vendor_net:s0 ro.emu. u:object_r:qemu_prop:s0 ro.emulator. u:object_r:qemu_prop:s0 ro.radio.noril u:object_r:radio_noril_prop:s0 net.eth0. u:object_r:net_eth0_prop:s0 -net.radio0. u:object_r:net_radio0_prop:s0 net.shared_net_ip u:object_r:net_share_prop:s0 ro.zygote.disable_gl_preload u:object_r:qemu_prop:s0 diff --git a/sepolicy/common/radio.te b/sepolicy/common/radio.te index 38faf6fa..742d3b2d 100644 --- a/sepolicy/common/radio.te +++ b/sepolicy/common/radio.te @@ -1,4 +1,3 @@ # Allow the radio to read these properties, they only have an SELinux label in # the emulator. get_prop(radio, net_eth0_prop); -allow radio net_radio0_prop:file { getattr read open map }; diff --git a/sepolicy/common/rild.te b/sepolicy/common/rild.te index c17fa5e7..ea183739 100644 --- a/sepolicy/common/rild.te +++ b/sepolicy/common/rild.te @@ -1,10 +1,3 @@ # Allow rild to read these properties, they only have an SELinux label in the # emulator. get_prop(rild, net_eth0_prop); -get_prop(rild, net_radio0_prop); - -# IPv6 router advertisement detection -allow rild self:packet_socket { bind create ioctl read setopt }; -allowxperm rild self:packet_socket ioctl { SIOCGIFFLAGS - SIOCSIFFLAGS - SIOCGIFHWADDR }; diff --git a/sepolicy/common/surfaceflinger.te b/sepolicy/common/surfaceflinger.te index 575ec1bd..2bba8a78 100644 --- a/sepolicy/common/surfaceflinger.te +++ b/sepolicy/common/surfaceflinger.te @@ -1,6 +1,5 @@ allow surfaceflinger self:process execmem; allow surfaceflinger ashmem_device:chr_file execute; -allow surfaceflinger gpu_device:chr_file { ioctl open read write map }; typeattribute surfaceflinger system_writes_vendor_properties_violators; set_prop(surfaceflinger, qemu_prop) diff --git a/sepolicy/common/wifi_forwarder.te b/sepolicy/common/wifi_forwarder.te deleted file mode 100644 index 3eb7bbac..00000000 --- a/sepolicy/common/wifi_forwarder.te +++ /dev/null @@ -1,11 +0,0 @@ -# Wifi forwarder -type wifi_forwarder, domain; -type wifi_forwarder_exec, exec_type, vendor_file_type, file_type; - -init_daemon_domain(wifi_forwarder) -net_domain(wifi_forwarder) - -allow wifi_forwarder self:capability { net_admin }; -# Generic netlink socket for wifi forwarding -allow wifi_forwarder self:netlink_generic_socket { bind create getattr setopt read write }; - diff --git a/sepolicy/x86/OWNERS b/sepolicy/x86/OWNERS index e6fbbd47..ff296774 100644 --- a/sepolicy/x86/OWNERS +++ b/sepolicy/x86/OWNERS @@ -3,7 +3,6 @@ bowgotsai@google.com jbires@google.com jeffv@google.com jgalenson@google.com -nnk@google.com sspatil@google.com tomcherry@google.com trong@google.com diff --git a/tnc/Android.bp b/tnc/Android.bp deleted file mode 100644 index fb0236fd..00000000 --- a/tnc/Android.bp +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (C) 2018 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -cc_binary { - name: "tnc", - vendor: true, - cflags: [ - "-Wall", - "-Werror", - ], - srcs: [ - "main.cpp", - ], - shared_libs: [ - "libcutils", - "liblog", - ], -} - diff --git a/tnc/main.cpp b/tnc/main.cpp deleted file mode 100644 index d6ffd116..00000000 --- a/tnc/main.cpp +++ /dev/null @@ -1,217 +0,0 @@ - -#include <errno.h> -#include <netdb.h> -#include <net/if.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -#include <initializer_list> - -static void usage(const char* program) { - fprintf(stderr, "Usage: %s [-s|-c|-b] <ip> <port>\n", program); -} - -enum class Mode { - Bridge, - Client, - Server, -}; - -bool resolve(const char* name, const char* port, struct addrinfo** addrs) { - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - - int res = ::getaddrinfo(name, port, &hints, addrs); - if (res != 0) { - fprintf(stderr, "ERROR: Unable to resolve '%s' and port '%s': %s\n", - name, port, gai_strerror(res)); - return false; - } - return true; -} - -int runClient(struct addrinfo* addrs) { - int fd = -1; - for (struct addrinfo* addr = addrs; addr != nullptr; addr = addr->ai_next) { - fd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); - if (fd < 0) { - continue; - } - if (::connect(fd, addr->ai_addr, addr->ai_addrlen) == 0) { - break; - } - ::close(fd); - } - ::freeaddrinfo(addrs); - if (fd < 0) { - fprintf(stderr, "Unable to connect to server\n"); - return 1; - } - if (::send(fd, "boop", 4, 0) != 4) { - ::close(fd); - fprintf(stderr, "Failed to send message to server\n"); - return 1; - } - ::close(fd); - return 0; -} - -int runServer(struct addrinfo* addrs) { - int fd = -1; - for (struct addrinfo* addr = addrs; addr != nullptr; addr = addr->ai_next) { - fd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); - if (fd < 0) { - continue; - } - if (::bind(fd, addr->ai_addr, addr->ai_addrlen) == 0) { - break; - } - ::close(fd); - } - ::freeaddrinfo(addrs); - if (fd < 0) { - fprintf(stderr, "Unable to bind to address\n"); - return 1; - } - char buffer[1024]; - for (;;) { - struct sockaddr_storage addr; - socklen_t addrSize = sizeof(addr); - ssize_t bytesRead = recvfrom(fd, buffer, sizeof(buffer), 0, - reinterpret_cast<struct sockaddr*>(&addr), - &addrSize); - if (bytesRead < 0) { - if (errno == EINTR) { - continue; - } - fprintf(stderr, "Error receiving on socket: %s\n", strerror(errno)); - ::close(fd); - return 1; - } else if (bytesRead == 0) { - fprintf(stderr, "Socket unexpectedly closed\n"); - ::close(fd); - return 1; - } - printf("Received message from client '%*s'\n", - static_cast<int>(bytesRead), buffer); - } -} - -static const char kBridgeName[] = "br0"; - -static int configureBridge() { - int fd = ::socket(AF_LOCAL, SOCK_STREAM, 0); - if (fd < 0) { - fprintf(stderr, "ERROR: Could not open bridge socket: %s\n", - strerror(errno)); - return 1; - } - - int res = ::ioctl(fd, SIOCBRADDBR, kBridgeName); - if (res < 0) { - fprintf(stderr, "ERROR: cannot create bridge: %s\n", strerror(errno)); - ::close(fd); - return 1; - } - - for (const auto& ifName : { "eth0", "wlan1", "radio0-peer" }) { - struct ifreq request; - memset(&request, 0, sizeof(request)); - request.ifr_ifindex = if_nametoindex(ifName); - if (request.ifr_ifindex == 0) { - fprintf(stderr, "ERROR: Unable to get interface index for %s\n", - ifName); - ::close(fd); - return 1; - } - strlcpy(request.ifr_name, kBridgeName, sizeof(request.ifr_name)); - res = ::ioctl(fd, SIOCBRADDIF, &request); - if (res < 0) { - fprintf(stderr, "ERROR: cannot add if %s to bridge: %s\n", - ifName, strerror(errno)); - ::close(fd); - return 1; - } - } - - struct ifreq request; - memset(&request, 0, sizeof(request)); - request.ifr_ifindex = if_nametoindex(kBridgeName); - if (request.ifr_ifindex == 0) { - fprintf(stderr, "ERROR: Unable to get interface index for %s\n", - kBridgeName); - ::close(fd); - return 1; - } - strlcpy(request.ifr_name, kBridgeName, sizeof(request.ifr_name)); - res = ::ioctl(fd, SIOCGIFFLAGS, &request); - if (res != 0) { - fprintf(stderr, "ERROR: Unable to get interface index for %s\n", - kBridgeName); - ::close(fd); - return 1; - } - if ((request.ifr_flags & IFF_UP) == 0) { - // Bridge is not up, it needs to be up to work - request.ifr_flags |= IFF_UP; - res = ::ioctl(fd, SIOCSIFFLAGS, &request); - if (res != 0) { - fprintf(stderr, "ERROR: Unable to set interface flags for %s\n", - kBridgeName); - ::close(fd); - return 1; - } - } - - ::close(fd); - return 0; -} - -int main(int argc, char* argv[]) { - if (argc < 2) { - usage(argv[0]); - return 1; - } - - Mode mode; - if (strcmp("-b", argv[1]) == 0) { - mode = Mode::Bridge; - } else if (strcmp("-c", argv[1]) == 0) { - mode = Mode::Client; - } else if (strcmp("-s", argv[1]) == 0) { - mode = Mode::Server; - } else { - fprintf(stderr, "ERROR: Invalid option '%s'\n", argv[1]); - usage(argv[0]); - return 1; - } - - struct addrinfo* addrs = nullptr; - if (mode == Mode::Client || mode == Mode::Server) { - if (argc != 4) { - usage(argv[0]); - return 1; - } - if (!resolve(argv[2], argv[3], &addrs)) { - usage(argv[0]); - return 1; - } - } - - switch (mode) { - case Mode::Bridge: - return configureBridge(); - case Mode::Client: - return runClient(addrs); - case Mode::Server: - return runServer(addrs); - } -} - diff --git a/tools/Android.bp b/tools/Android.bp deleted file mode 100644 index 8cb1ad02..00000000 --- a/tools/Android.bp +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -python_binary_host { - name: "mk_combined_img", - srcs: ["mk_combined_img.py"], - main: "mk_combined_img.py", - version: { - py2: { - enabled: true, - embedded_launcher: true, - }, - py3: { - enabled: false, - }, - }, -} diff --git a/tools/Android.mk b/tools/Android.mk deleted file mode 100644 index 928fc9d0..00000000 --- a/tools/Android.mk +++ /dev/null @@ -1,97 +0,0 @@ -# -# Copyright 2019 The Android Open-Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -ifneq ($(filter generic_% generic, $(TARGET_DEVICE)),) -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -EMU_EXTRA_FILES := \ - $(PRODUCT_OUT)/system-qemu-config.txt \ - $(PRODUCT_OUT)/ramdisk.img \ - $(PRODUCT_OUT)/misc_info.txt \ - -ifeq ($(filter sdk_gphone_%, $(TARGET_PRODUCT)),) -ifeq ($(TARGET_BUILD_VARIANT),user) -EMU_EXTRA_FILES += device/generic/goldfish/data/etc/user/advancedFeatures.ini -else -EMU_EXTRA_FILES += device/generic/goldfish/data/etc/advancedFeatures.ini -endif -else -ifeq ($(TARGET_BUILD_VARIANT),user) -EMU_EXTRA_FILES += device/generic/goldfish/data/etc/google/user/advancedFeatures.ini -else -EMU_EXTRA_FILES += device/generic/goldfish/data/etc/google/userdebug/advancedFeatures.ini -endif -endif - -EMU_EXTRA_FILES += device/generic/goldfish/data/etc/config.ini -EMU_EXTRA_FILES += device/generic/goldfish/data/etc/encryptionkey.img -EMU_EXTRA_FILES += device/generic/goldfish/data/etc/userdata.img - -name := emu-extra-linux-system-images-$(FILE_NAME_TAG) - -EMU_EXTRA_TARGET := $(PRODUCT_OUT)/$(name).zip - -EMULATOR_KERNEL_ARCH := $(TARGET_ARCH) -EMULATOR_KERNEL_DIST_NAME := kernel-ranchu -EMULATOR_KERNEL_VERSION := 3.18 - -# Use 64-bit kernel even for 32-bit Android -ifeq ($(TARGET_ARCH), x86) -EMULATOR_KERNEL_ARCH := x86_64 -EMULATOR_KERNEL_DIST_NAME := kernel-ranchu-64 -endif -ifeq ($(TARGET_ARCH), arm) -EMULATOR_KERNEL_ARCH := arm64 -EMULATOR_KERNEL_DIST_NAME := kernel-ranchu-64 -endif - -# Below should be the same as PRODUCT_KERNEL_VERSION set in -# device/generic/goldfish/arm*-vendor.mk -ifneq ($(filter $(TARGET_ARCH), arm arm64),) -EMULATOR_KERNEL_VERSION := 4.4 -endif -# Below should be the same as PRODUCT_KERNEL_VERSION set in -# device/generic/goldfish/x86*-vendor.mk -ifneq ($(filter $(TARGET_ARCH), x86 x86_64),) -EMULATOR_KERNEL_VERSION := 4.14 -endif - -EMULATOR_KERNEL_FILE := prebuilts/qemu-kernel/$(EMULATOR_KERNEL_ARCH)/$(EMULATOR_KERNEL_VERSION)/kernel-qemu2 - -$(EMU_EXTRA_TARGET): PRIVATE_PACKAGE_SRC := \ - $(call intermediates-dir-for, PACKAGING, emu_extra_target) - -$(EMU_EXTRA_TARGET): $(EMU_EXTRA_FILES) $(EMULATOR_KERNEL_FILE) $(AVBTOOL) $(SOONG_ZIP) - @echo "Package: $@" - rm -rf $@ $(PRIVATE_PACKAGE_SRC) - mkdir -p $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH)/prebuilts/qemu-kernel/$(TARGET_ARCH) - touch $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH)/prebuilts/qemu-kernel/$(TARGET_ARCH)/kernel-qemu - $(foreach f,$(EMU_EXTRA_FILES), cp $(f) $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH)/$(notdir $(f)) &&) true - cp $(EMULATOR_KERNEL_FILE) $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH)/${EMULATOR_KERNEL_DIST_NAME} - cp -r $(PRODUCT_OUT)/data $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH) - mkdir -p $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH)/system - cp $(PRODUCT_OUT)/system/build.prop $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH)/system - $(AVBTOOL) make_vbmeta_image --flag 2 --padding_size 4096 --output $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH)/vbmeta-disabled.img - $(SOONG_ZIP) -o $@ -C $(PRIVATE_PACKAGE_SRC) -D $(PRIVATE_PACKAGE_SRC)/$(TARGET_ARCH) - -.PHONY: emu_extra_imgs -emu_extra_imgs: $(EMU_EXTRA_TARGET) - -$(call dist-for-goals, emu_extra_imgs, $(EMU_EXTRA_TARGET)) - -include $(call all-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/tools/extract_head_tail.sh b/tools/extract_head_tail.sh deleted file mode 100755 index 5941da74..00000000 --- a/tools/extract_head_tail.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -set -e - -if [ "$#" -ne 3 ]; then - echo "$0 src.img head.img tail.img" >&2 - exit 1 -fi - -srcimg=$1 -headimg=$2 -tailimg=$3 - -disksize=$(stat -c %s $srcimg) - -mycount=`expr $disksize \/ 1024 \/ 1024 - 1` - -dd if=$srcimg of=$headimg ibs=1M obs=1M count=1 -dd if=$srcimg of=$tailimg ibs=1M obs=1M count=1 skip=$mycount -#dd if=/dev/zero of=file.txt count=3083 bs=1M diff --git a/tools/mk_combined_img.py b/tools/mk_combined_img.py index 1e35dc67..1b7bbff0 100755 --- a/tools/mk_combined_img.py +++ b/tools/mk_combined_img.py @@ -1,33 +1,26 @@ #!/usr/bin/python - -from __future__ import print_function - -import argparse -import codecs -import operator -import os import sys +import os from subprocess import Popen, PIPE from tempfile import mkstemp +import argparse +import operator def check_sparse(filename): magic = 3978755898 with open(filename, 'rb') as i: word = i.read(4) - if magic == int(codecs.encode(word[::-1], 'hex'), 16): + if magic == int(word[::-1].encode('hex'), 16): return True return False - def shell_command(comm_list): - command = Popen(comm_list, stdout=PIPE, stderr=PIPE) - command.communicate() - command.wait() + command = Popen(comm_list) + execute = command.wait() if command.returncode != 0: sys.exit(1) - def parse_input(input_file): parsed_lines = list() lines = input_file.readlines() @@ -46,27 +39,24 @@ def parse_input(input_file): num_used = set() for line in parsed_lines: partition_info = dict() - partition_info["path"] = line[0] + partition_info["path"] = line[0] partition_info["label"] = line[1] - # round up by 1M - sizeByMb = str((1024 * 1024 - 1 + os.path.getsize(line[0])) / 1024 / 1024) - partition_info["sizeByMb"] = sizeByMb try: partition_info["num"] = int(line[2]) except ValueError: - print("'%s' cannot be converted to int" % (line[2])) + print "'%s' cannot be converted to int" % (line[2]) sys.exit(1) # check if the partition number is out of range if partition_info["num"] > len(lines) or partition_info["num"] < 0: - print("Invalid partition number: %d, range [1..%d]" % \ - (partition_info["num"], len(lines))) + print "Invalid partition number: %d, range [1..%d]" % \ + (partition_info["num"], len(lines)) sys.exit(1) # check if the partition number is duplicated if partition_info["num"] in num_used: - print("Duplicated partition number:%d" % (partition_info["num"])) + print "Duplicated partition number:%d" % (partition["num"]) sys.exit(1) num_used.add(partition_info["num"]) partitions.append(partition_info) @@ -74,47 +64,42 @@ def parse_input(input_file): partitions.sort(key=operator.itemgetter("num")) return partitions - def write_partition(partition, output_file, offset): # $ dd if=/path/to/image of=/path/to/output conv=notrunc,sync \ # ibs=1024k obs=1024k seek=<offset> - dd_comm = ['dd', 'if=' + partition["path"], 'of=' + output_file, 'conv=notrunc,sync', - 'ibs=1024k', 'obs=1024k', 'seek=' + str(offset)] + dd_comm = ['dd', 'if='+partition["path"], 'of='+output_file,'conv=notrunc,sync', + 'ibs=1024k','obs=1024k', 'seek='+str(offset)] shell_command(dd_comm) return - def unsparse_partition(partition): # if the input image is in sparse format, unsparse it simg2img = os.environ.get('SIMG2IMG', 'simg2img') - print("Unsparsing %s" % (partition["path"]), end=' ') + print "Unsparsing %s" % (partition["path"]), partition["fd"], temp_file = mkstemp() shell_command([simg2img, partition["path"], temp_file]) partition["path"] = temp_file - print("Done") + print "Done" return - def clear_partition_table(filename): sgdisk = os.environ.get('SGDISK', 'sgdisk') - print("%s --clear %s" % (sgdisk, filename)) + print "%s --clear %s" % (sgdisk, filename) shell_command([sgdisk, '--clear', filename]) return - def add_partition(partition, output_file): sgdisk = os.environ.get('SGDISK', 'sgdisk') num = str(partition["num"]) - new_comm = '--new=' + num + ':' + partition["start"] + ':' + partition["end"] - type_comm = '--type=' + num + ':8300' - name_comm = '--change-name=' + num + ':' + partition["label"] + new_comm = '--new='+num+':'+partition["start"]+':'+partition["end"] + type_comm = '--type='+num+':8300' + name_comm = '--change-name='+num+':'+partition["label"] # build partition table in order. for example: # $ sgdisk --new=1:2048:5244927 --type=1:8300 --change-name=1:system \ # /path/to/output shell_command([sgdisk, new_comm, type_comm, name_comm, output_file]) return - def main(): # check usage: parser = argparse.ArgumentParser() @@ -123,19 +108,15 @@ def main(): default="image_config") parser.add_argument("-o", "--output", type=str, help="output filename", - default=os.environ.get("OUT", ".") + "/combined.img") + default=os.environ.get("OUT", ".")+"/combined.img") args = parser.parse_args() output_filename = os.path.expandvars(args.output) - # remove the output_filename.qcow2 - print("removing " + output_filename + ".qcow2") - shell_command(['rm', '-rf', output_filename + ".qcow2"]) - # check input file config_filename = args.input if not os.path.exists(config_filename): - print("Invalid config file name " + config_filename) + print "Invalid config file name " + config_filename sys.exit(1) # read input file @@ -143,57 +124,29 @@ def main(): partitions = parse_input(config) config.close() - # take a shortcut in build environment - if os.path.exists(output_filename) and len(partitions) == 2: - print("updating " + output_filename + " ...") - shell_command(['dd', "if=" + partitions[0]["path"], "of=" + output_filename, - "conv=notrunc,sync", "ibs=1024k", "obs=1024k", "seek=1"]) - shell_command(['dd', "if=" + partitions[1]["path"], "of=" + output_filename, - "conv=notrunc,sync", "ibs=1024k", "obs=1024k", "seek=2"]) - print("done") - sys.exit(0) - elif len(partitions) == 2: - gptprefix = partitions[0]["sizeByMb"] + "_" + partitions[1]["sizeByMb"] - prebuilt_gpt_dir = os.path.dirname(os.path.abspath( __file__ )) + "/prebuilt/gpt/" + gptprefix - gpt_head = prebuilt_gpt_dir + "/head.img" - gpt_tail = prebuilt_gpt_dir + "/head.img" - if os.path.exists(gpt_head) and os.path.exists(gpt_tail): - print("found prebuilt gpt header and footer, use it") - shell_command(['dd', "if=" + gpt_head, "of=" + output_filename, "bs=1024k", - "conv=notrunc,sync", "count=1"]) - shell_command(['dd', "if=" + partitions[0]["path"], "of=" + output_filename, - "bs=1024k", "conv=notrunc,sync", "seek=1"]) - shell_command(['dd', "if=" + partitions[1]["path"], "of=" + output_filename, - "bs=1024k", "conv=notrunc,sync", "seek=" + str(1 + int(partitions[0]["sizeByMb"]))]) - shell_command(['dd', "if=" + gpt_tail, "of=" + output_filename, - "bs=1024k", "conv=notrunc,sync", - "seek=" + str(1 + int(partitions[0]["sizeByMb"]) + int(partitions[1]["sizeByMb"]))]) - print("done") - sys.exit(0) - # combine the images # add padding - shell_command(['dd', 'if=/dev/zero', 'of=' + output_filename, 'ibs=1024k', 'count=1']) + shell_command(['dd', 'if=/dev/zero', 'of='+output_filename, 'ibs=1024k', 'count=1']) for partition in partitions: offset = os.path.getsize(output_filename) - partition["start"] = str(offset // 512) + partition["start"] = str(offset / 512) # dectect sparse file format if check_sparse(partition["path"]): unsparse_partition(partition) # TODO: extract the partition if the image file is already formatted - write_partition(partition, output_filename, offset // 1024 // 1024) + write_partition(partition, output_filename, offset/1024/1024) offset = os.path.getsize(output_filename) - partition["end"] = str(offset // 512 - 1) + partition["end"] = str(offset / 512 - 1) # add padding # $ dd if=/dev/zero of=/path/to/output conv=notrunc bs=1 \ # count=1024k seek=<offset> - offset = os.path.getsize(output_filename) // 1024 // 1024 - shell_command(['dd', 'if=/dev/zero', 'of=' + output_filename, - 'conv=notrunc', 'bs=1024k', 'count=1', 'seek=' + str(offset)]) + offset = os.path.getsize(output_filename) / 1024 / 1024 + shell_command(['dd', 'if=/dev/zero', 'of='+output_filename, + 'conv=notrunc', 'bs=1024k', 'count=1', 'seek='+str(offset)]) # make partition table # $ sgdisk --clear /path/to/output @@ -206,6 +159,6 @@ def main(): os.close(partition["fd"]) os.remove(partition["path"]) - if __name__ == "__main__": main() + diff --git a/tools/mk_qemu_image.sh b/tools/mk_qemu_image.sh index 87e0a8a3..0f26173c 100755 --- a/tools/mk_qemu_image.sh +++ b/tools/mk_qemu_image.sh @@ -32,7 +32,14 @@ fi dd if=/dev/zero of=$target ibs=1024k count=1 > /dev/null 2>&1 dd if=$srcimg of=$target conv=notrunc,sync ibs=1024k obs=1024k seek=1 > /dev/null 2>&1 unamestr=`uname` +if [[ "$unamestr" == 'Linux' ]]; then curdisksize=$(stat -c %s $target) +elif [[ "$unamestr" == 'Darwin' ]]; then +curdisksize=$(stat -f %z $target) +else +echo "Cannot determine OS type, quit" +exit 1 +fi dd if=/dev/zero of=$target conv=notrunc bs=1 count=1024k seek=$curdisksize > /dev/null 2>&1 diff --git a/tools/mk_vbmeta_boot_params.sh b/tools/mk_vbmeta_boot_params.sh index e436923a..17a39e8e 100755 --- a/tools/mk_vbmeta_boot_params.sh +++ b/tools/mk_vbmeta_boot_params.sh @@ -2,7 +2,7 @@ if [ $# -ne 3 ]; then echo "Usage: $0 <vbmeta.img> <system.img> <VbmetaBootParams.textproto>" - exit 0 + exit 1 fi # Example Output from 'avbtool calculate_vbmeta_digest --image $OUT/vbmeta.img': @@ -42,11 +42,14 @@ readonly TARGET=$3 # Extract the digest readonly VBMETA_DIGEST=$(${AVBTOOL:-avbtool} calculate_vbmeta_digest --image $VBMETAIMG) +echo "digest is $VBMETA_DIGEST" readonly INFO_OUTPUT=$(${AVBTOOL:-avbtool} info_image --image $VBMETAIMG | grep "^Algorithm:") +echo "output is $INFO_OUTPUT" # Extract the algorithm readonly ALG_OUTPUT=$(echo $INFO_OUTPUT | grep "Algorithm:") +echo \"$ALG_OUTPUT\" readonly ALG_SPLIT=($(echo $ALG_OUTPUT | tr ' ' '\n')) readonly ORG_ALGORITHM=${ALG_SPLIT[1]} @@ -56,6 +59,7 @@ else die "Don't know anything about $ORG_ALGORITHM" fi +echo "hash algorithm is $VBMETA_HASH_ALG" # extract the size @@ -73,6 +77,7 @@ SYSMETA_SIZE=$(get_bytes $SYSIMG "VBMeta size:") VBMETA_SIZE=$(expr $HEADER_SIZE + $AUTHEN_SIZE + $AUX_SIZE + $SYSMETA_SIZE) +echo "vbmeta size $VBMETA_SIZE" HEADER_COMMENT="# androidboot.vbmeta.size=$VBMETA_SIZE androidboot.vbmeta.hash_alg=$VBMETA_HASH_ALG androidboot.vbmeta.digest=$VBMETA_DIGEST" diff --git a/tools/prebuilt/gpt/1_3080/head.img b/tools/prebuilt/gpt/1_3080/head.img Binary files differdeleted file mode 100644 index f16ea54e..00000000 --- a/tools/prebuilt/gpt/1_3080/head.img +++ /dev/null diff --git a/tools/prebuilt/gpt/1_3080/tail.img b/tools/prebuilt/gpt/1_3080/tail.img Binary files differdeleted file mode 100644 index 2f698290..00000000 --- a/tools/prebuilt/gpt/1_3080/tail.img +++ /dev/null diff --git a/ueventd.goldfish.rc b/ueventd.goldfish.rc index 0335d0b1..8674767a 100644 --- a/ueventd.goldfish.rc +++ b/ueventd.goldfish.rc @@ -4,3 +4,4 @@ /dev/goldfish_pipe 0666 system system /dev/goldfish_address_space 0666 system system /dev/ttyS* 0666 system system +/proc 0666 system system diff --git a/ueventd.ranchu.rc b/ueventd.ranchu.rc index db426342..0ad6230b 100644 --- a/ueventd.ranchu.rc +++ b/ueventd.ranchu.rc @@ -2,8 +2,6 @@ /dev/qemu_trace 0666 system system /dev/goldfish_pipe 0666 system system /dev/ttyS* 0666 system system +/proc 0666 system system /dev/goldfish_sync 0666 system system /dev/goldfish_address_space 0666 system system -/dev/dri/card0 0660 system graphics -/dev/dri/controlD64 0660 system graphics -/dev/dri/renderD128 0666 system graphics @@ -17,45 +17,31 @@ # This file is to configure vendor/data partitions of emulator-related products # -ifeq ($(QEMU_DISABLE_AVB),true) - ifeq ($(QEMU_USE_SYSTEM_EXT_PARTITIONS),true) - PRODUCT_COPY_FILES += \ - device/generic/goldfish/data/etc/dummy.vbmeta.img:$(PRODUCT_OUT)/vbmeta.img \ - device/generic/goldfish/fstab.ranchu.initrd.noavb.ex:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ - device/generic/goldfish/fstab.ranchu.noavb.ex:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu - else - PRODUCT_COPY_FILES += \ - device/generic/goldfish/data/etc/dummy.vbmeta.img:$(PRODUCT_OUT)/vbmeta.img \ - device/generic/goldfish/fstab.ranchu.initrd.noavb:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ - device/generic/goldfish/fstab.ranchu.noavb:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu - endif -endif - -ifeq ($(QEMU_USE_SYSTEM_EXT_PARTITIONS),true) -PRODUCT_COPY_FILES += \ - device/generic/goldfish/fstab.ranchu.initrd.ex:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ - device/generic/goldfish/fstab.ranchu.ex:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu -endif - - -DISABLE_RILD_OEM_HOOK := true - -DEVICE_MANIFEST_FILE := device/generic/goldfish/manifest.xml - # Device modules PRODUCT_PACKAGES += \ vulkan.ranchu \ gralloc.goldfish \ gralloc.goldfish.default \ gralloc.ranchu \ - libandroidemu \ + libGLESv1_CM_emulation \ + lib_renderControl_enc \ + libEGL_emulation \ + libGLESv2_enc \ + libvulkan_enc \ libOpenglCodecCommon \ libOpenglSystemCommon \ + libGLESv2_emulation \ + libGLESv1_enc \ libEGL_swiftshader \ libGLESv1_CM_swiftshader \ libGLESv2_swiftshader \ libgoldfish-ril \ qemu-props \ + camera.goldfish \ + camera.goldfish.jpeg \ + camera.ranchu \ + camera.ranchu.jpeg \ + gatekeeper.ranchu \ gps.goldfish \ gps.ranchu \ fingerprint.goldfish \ @@ -64,8 +50,9 @@ PRODUCT_PACKAGES += \ power.goldfish \ power.ranchu \ fingerprint.ranchu \ - android.hardware.graphics.composer@2.3-impl \ - android.hardware.graphics.composer@2.3-service \ + sensors.ranchu \ + android.hardware.graphics.composer@2.1-impl \ + android.hardware.graphics.composer@2.1-service \ android.hardware.graphics.allocator@2.0-service \ android.hardware.graphics.allocator@2.0-impl \ android.hardware.graphics.mapper@2.0-impl \ @@ -76,23 +63,10 @@ PRODUCT_PACKAGES += \ android.hardware.wifi@1.0-service \ android.hardware.biometrics.fingerprint@2.1-service \ sh_vendor \ - ip_vendor \ iw_vendor \ audio.r_submix.default \ local_time.default \ - SdkSetup \ - MultiDisplayProvider - -ifneq ($(BUILD_EMULATOR_OPENGL),false) -PRODUCT_PACKAGES += \ - libGLESv1_CM_emulation \ - lib_renderControl_enc \ - libEGL_emulation \ - libGLESv2_enc \ - libvulkan_enc \ - libGLESv2_emulation \ - libGLESv1_enc -endif + SdkSetup PRODUCT_PACKAGES += \ android.hardware.audio@4.0-impl:32 \ @@ -105,8 +79,8 @@ PRODUCT_PACKAGES += \ android.hardware.health@2.0-service.goldfish PRODUCT_PACKAGES += \ - android.hardware.keymaster@4.0-impl \ - android.hardware.keymaster@4.0-service + android.hardware.keymaster@3.0-impl \ + android.hardware.keymaster@3.0-service PRODUCT_PACKAGES += \ DisplayCutoutEmulationEmu01Overlay @@ -115,16 +89,12 @@ ifneq ($(EMULATOR_VENDOR_NO_GNSS),true) PRODUCT_PACKAGES += \ android.hardware.gnss@1.0-service \ android.hardware.gnss@1.0-impl -DEVICE_MANIFEST_FILE += device/generic/goldfish/manifest.gnss.xml endif -ifneq ($(EMULATOR_VENDOR_NO_SENSORS),true) + PRODUCT_PACKAGES += \ android.hardware.sensors@1.0-impl \ - android.hardware.sensors@1.0-service \ - sensors.ranchu -DEVICE_MANIFEST_FILE += device/generic/goldfish/manifest.sensors.xml -endif + android.hardware.sensors@1.0-service PRODUCT_PACKAGES += \ android.hardware.drm@1.0-service \ @@ -137,41 +107,42 @@ PRODUCT_PACKAGES += \ PRODUCT_PROPERTY_OVERRIDES += ro.control_privapp_permissions=enforce PRODUCT_PROPERTY_OVERRIDES += ro.hardware.power=ranchu +PRODUCT_PROPERTY_OVERRIDES += ro.crypto.volume.filenames_mode=aes-256-cts PRODUCT_PROPERTY_OVERRIDES += persist.sys.zram_enabled=1 \ -ifneq ($(EMULATOR_VENDOR_NO_CAMERA),true) PRODUCT_PACKAGES += \ camera.device@1.0-impl \ android.hardware.camera.provider@2.4-service \ android.hardware.camera.provider@2.4-impl \ - camera.goldfish \ - camera.goldfish.jpeg \ - camera.ranchu \ - camera.ranchu.jpeg -DEVICE_MANIFEST_FILE += device/generic/goldfish/manifest.camera.xml -endif PRODUCT_PACKAGES += \ - android.hardware.gatekeeper@1.0-service.software + android.hardware.gatekeeper@1.0-impl \ + android.hardware.gatekeeper@1.0-service # WiFi: vendor side PRODUCT_PACKAGES += \ createns \ dhcpclient \ + dhcpserver \ execns \ hostapd \ hostapd_nohidl \ + ipv6proxy \ netmgr \ - wifi_forwarder \ wpa_supplicant \ PRODUCT_PACKAGES += android.hardware.thermal@2.0-service.mock +# Needed for /system/priv-app/SdkSetup/SdkSetup.apk to pass CTS android.permission2.cts.PrivappPermissionsTest. +PRODUCT_COPY_FILES += \ + device/generic/goldfish/data/etc/permissions/privapp-permissions-goldfish.xml:$(TARGET_COPY_OUT_SYSTEM)/etc/permissions/privapp-permissions-goldfish.xml + # Goldfish does not support ION needed for Codec 2.0 PRODUCT_PROPERTY_OVERRIDES += \ debug.stagefright.ccodec=0 + PRODUCT_COPY_FILES += \ device/generic/goldfish/fstab.ranchu.initrd:$(TARGET_COPY_OUT_RAMDISK)/fstab.ranchu \ device/generic/goldfish/data/etc/apns-conf.xml:data/misc/apns/apns-conf.xml \ @@ -183,8 +154,6 @@ PRODUCT_COPY_FILES += \ device/generic/goldfish/fstab.ranchu:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.ranchu \ device/generic/goldfish/ueventd.ranchu.rc:$(TARGET_COPY_OUT_VENDOR)/ueventd.rc \ device/generic/goldfish/input/goldfish_rotary.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/goldfish_rotary.idc \ - device/generic/goldfish/input/qwerty2.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/qwerty2.idc \ - device/generic/goldfish/input/qwerty.kl:$(TARGET_COPY_OUT_VENDOR)/usr/keylayout/qwerty.kl \ device/generic/goldfish/input/virtio_input_multi_touch_1.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_1.idc \ device/generic/goldfish/input/virtio_input_multi_touch_2.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_2.idc \ device/generic/goldfish/input/virtio_input_multi_touch_3.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_3.idc \ @@ -196,6 +165,7 @@ PRODUCT_COPY_FILES += \ device/generic/goldfish/input/virtio_input_multi_touch_9.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_9.idc \ device/generic/goldfish/input/virtio_input_multi_touch_10.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_10.idc \ device/generic/goldfish/input/virtio_input_multi_touch_11.idc:$(TARGET_COPY_OUT_VENDOR)/usr/idc/virtio_input_multi_touch_11.idc \ + device/generic/goldfish/manifest.xml:$(TARGET_COPY_OUT_VENDOR)/manifest.xml \ device/generic/goldfish/data/etc/config.ini:config.ini \ device/generic/goldfish/wifi/simulated_hostapd.conf:$(TARGET_COPY_OUT_VENDOR)/etc/simulated_hostapd.conf \ device/generic/goldfish/wifi/wpa_supplicant.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/wpa_supplicant.conf \ @@ -206,8 +176,7 @@ PRODUCT_COPY_FILES += \ device/generic/goldfish/camera/media_profiles.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_V1_0.xml \ frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_google_audio.xml \ frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_google_telephony.xml \ - device/generic/goldfish/camera/media_codecs_google_video_default.xml:data/vendor/etc/media_codecs_google_video_default.xml \ - device/generic/goldfish/camera/media_codecs_google_video_v2.xml:data/vendor/etc/media_codecs_google_video_v2.xml \ + device/generic/goldfish/camera/media_codecs_google_video.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_google_video.xml \ device/generic/goldfish/camera/media_codecs.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs.xml \ device/generic/goldfish/camera/media_codecs_performance.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_performance.xml \ frameworks/native/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.xml \ @@ -215,11 +184,8 @@ PRODUCT_COPY_FILES += \ frameworks/native/data/etc/android.hardware.camera.autofocus.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.autofocus.xml \ frameworks/native/data/etc/android.hardware.camera.full.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.full.xml \ frameworks/native/data/etc/android.hardware.fingerprint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.fingerprint.xml \ - frameworks/native/data/etc/android.hardware.vulkan.level-1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.level.xml \ - frameworks/native/data/etc/android.hardware.vulkan.compute-0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.compute.xml \ - frameworks/native/data/etc/android.hardware.vulkan.version-1_1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml \ frameworks/native/data/etc/android.software.autofill.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.autofill.xml \ - frameworks/native/data/etc/android.software.verified_boot.xml:${TARGET_COPY_OUT_PRODUCT}/etc/permissions/android.software.verified_boot.xml \ + frameworks/native/data/etc/android.software.verified_boot.xml:system/etc/permissions/android.software.verified_boot.xml \ frameworks/av/media/libeffects/data/audio_effects.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_effects.xml \ device/generic/goldfish/audio_policy.conf:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy.conf \ frameworks/av/services/audiopolicy/config/audio_policy_configuration_generic.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_configuration.xml \ @@ -228,4 +194,3 @@ PRODUCT_COPY_FILES += \ frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_volumes.xml \ frameworks/av/services/audiopolicy/config/default_volume_tables.xml:$(TARGET_COPY_OUT_VENDOR)/etc/default_volume_tables.xml \ frameworks/av/services/audiopolicy/config/surround_sound_configuration_5_0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/surround_sound_configuration_5_0.xml \ - device/generic/goldfish/data/etc/permissions/privapp-permissions-goldfish.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/permissions/privapp-permissions-goldfish.xml diff --git a/wifi/createns/createns.cpp b/wifi/createns/createns.cpp index 95aff530..66f6dd3d 100644 --- a/wifi/createns/createns.cpp +++ b/wifi/createns/createns.cpp @@ -103,8 +103,8 @@ static bool writeNamespacePid(const char* name, pid_t pid) { path += ".pid"; Fd fd(::open(path.c_str(), - O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, - S_IRUSR | S_IWUSR | S_IRGRP)); + O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, + S_IRUSR | S_IRGRP | S_IROTH)); if (fd.get() == -1) { ALOGE("Unable to create file '%s': %s", path.c_str(), strerror(errno)); return false; @@ -223,7 +223,6 @@ int main(int argc, char* argv[]) { ALOGE("Failed to create pipe: %s", strerror(errno)); return 1; } - Fd readPipe(fds[0]); Fd writePipe(fds[1]); @@ -240,8 +239,7 @@ int main(int argc, char* argv[]) { } { // Open and then immediately close the fd - Fd fd(::open(path.c_str(), O_CREAT | O_TRUNC | O_RDONLY | O_CLOEXEC, - S_IRUSR | S_IWUSR | S_IRGRP)); + Fd fd(::open(path.c_str(), O_CREAT | O_EXCL | O_RDONLY | O_CLOEXEC, 0)); if (fd.get() == -1) { ALOGE("Failed to open file %s: %s", path.c_str(), strerror(errno)); return 1; diff --git a/wifi/init.wifi.sh b/wifi/init.wifi.sh index fd84d12d..ff64e91f 100755 --- a/wifi/init.wifi.sh +++ b/wifi/init.wifi.sh @@ -42,43 +42,70 @@ # NAMESPACE="router" +rm -rf /data/vendor/var/run/netns/${NAMESPACE} +rm -rf /data/vendor/var/run/netns/${NAMESPACE}.pid +# Lower the MTU of the WiFi interface to prevent issues with packet injection. +# The MTU of the WiFi monitor interface cannot be higher than 1500 but injection +# requires extra space for injection headers which count against the MTU. So if +# a 1500 byte payload needs to be injected it will fail because with the +# additional headers the total amount of data will exceed 1500 bytes. This way +# the payload is restricted to a smaller size that should leave room for the +# injection headers. +/system/bin/ip link set wlan0 mtu 1400 createns ${NAMESPACE} +# If this is a clean boot we need to copy the hostapd configuration file to the +# data partition where netmgr can change it if needed. If it already exists we +# need to preserve the existing settings. +if [ ! -f /data/vendor/wifi/hostapd/hostapd.conf ]; then + cp /vendor/etc/simulated_hostapd.conf /data/vendor/wifi/hostapd/hostapd.conf + chown wifi:wifi /data/vendor/wifi/hostapd/hostapd.conf + chmod 660 /data/vendor/wifi/hostapd/hostapd.conf +fi + # createns will have created a file that contains the process id (pid) of a # process running in the network namespace. This pid is needed for some commands # to access the namespace. -PID=$(</data/vendor/var/run/netns/${NAMESPACE}.pid) +PID=$(cat /data/vendor/var/run/netns/${NAMESPACE}.pid) -/vendor/bin/ip link set eth0 netns ${PID} +# Move the WiFi monitor interface to the other namespace and bring it up. This +# is what we use for injecting WiFi frames from the outside world. +/system/bin/ip link set hwsim0 netns ${PID} +execns ${NAMESPACE} /system/bin/ip link set hwsim0 up -/vendor/bin/ip link add radio0 type veth peer name radio0-peer netns ${PID} +# Start the network manager as soon as possible after the namespace is available. +# This ensures that anything that follows is properly managed and monitored. +setprop ctl.start netmgr +/system/bin/ip link set eth0 netns ${PID} +/system/bin/ip link add radio0 type veth peer name radio0-peer +/system/bin/ip link set radio0-peer netns ${PID} # Enable privacy addresses for radio0, this is done by the framework for wlan0 sysctl -wq net.ipv6.conf.radio0.use_tempaddr=2 - -execns ${NAMESPACE} /vendor/bin/ip link set radio0-peer up - -execns ${NAMESPACE} /vendor/bin/ip link set eth0 up - -/vendor/bin/ip link set radio0 up - -execns ${NAMESPACE} /vendor/bin/ip link set wlan1 up - +/system/bin/ip addr add 192.168.200.2/24 broadcast 192.168.200.255 dev radio0 +execns ${NAMESPACE} /system/bin/ip addr add 192.168.200.1/24 dev radio0-peer +execns ${NAMESPACE} sysctl -wq net.ipv6.conf.all.forwarding=1 +execns ${NAMESPACE} /system/bin/ip link set radio0-peer up +# Start the dhcp client for eth0 to acquire an address +setprop ctl.start dhcpclient_rtr +# Create iptables entries. -w will cause an indefinite wait for the exclusive +# lock. Without this flag iptables can sporadically fail if something else is +# modifying the iptables at the same time. -W indicates the number of micro- +# seconds between each retry. The default is one second which seems like a long +# time. Keep this short so we don't slow down startup too much. +execns ${NAMESPACE} /system/bin/iptables -w -W 50000 -t nat -A POSTROUTING -s 192.168.232.0/21 -o eth0 -j MASQUERADE +execns ${NAMESPACE} /system/bin/iptables -w -W 50000 -t nat -A POSTROUTING -s 192.168.200.0/24 -o eth0 -j MASQUERADE /vendor/bin/iw phy phy1 set netns $PID -setprop ctl.start netmgr - -setprop ctl.start wifi_forwarder - -# If this is a clean boot we need to copy the hostapd configuration file to the -# data partition where netmgr can change it if needed. If it already exists we -# need to preserve the existing settings. -if [ ! -f /data/vendor/wifi/hostapd/hostapd.conf ]; then - cp /vendor/etc/simulated_hostapd.conf /data/vendor/wifi/hostapd/hostapd.conf - chown wifi:wifi /data/vendor/wifi/hostapd/hostapd.conf - chmod 660 /data/vendor/wifi/hostapd/hostapd.conf -fi - +execns ${NAMESPACE} /system/bin/ip addr add 192.168.232.1/21 dev wlan1 +execns ${NAMESPACE} /system/bin/ip link set wlan1 mtu 1400 +execns ${NAMESPACE} /system/bin/ip link set wlan1 up +# Start the IPv6 proxy that will enable use of IPv6 in the main namespace +setprop ctl.start ipv6proxy +execns ${NAMESPACE} sysctl -wq net.ipv4.ip_forward=1 # Start hostapd, the access point software setprop ctl.start emu_hostapd +# Start DHCP server for the wifi interface +setprop ctl.start dhcpserver +/system/bin/ip link set radio0 up diff --git a/wifi/ipv6proxy/Android.mk b/wifi/ipv6proxy/Android.mk new file mode 100644 index 00000000..a1695d6c --- /dev/null +++ b/wifi/ipv6proxy/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + address.cpp \ + interface.cpp \ + log.cpp \ + main.cpp \ + namespace.cpp \ + packet.cpp \ + proxy.cpp \ + router.cpp \ + socket.cpp \ + + +LOCAL_CPPFLAGS += -Werror +LOCAL_SHARED_LIBRARIES := libcutils liblog +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := ipv6proxy + +LOCAL_MODULE_CLASS := EXECUTABLES + +include $(BUILD_EXECUTABLE) diff --git a/wifi/ipv6proxy/address.cpp b/wifi/ipv6proxy/address.cpp new file mode 100644 index 00000000..def9c7b8 --- /dev/null +++ b/wifi/ipv6proxy/address.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "address.h" + +#include <arpa/inet.h> +#include <errno.h> +#include <linux/if_ether.h> +#include <linux/if_packet.h> +#include <netdb.h> +#include <net/if.h> +#include <string.h> +#include <sys/ioctl.h> + +#include "socket.h" + +std::string addrToStr(const struct in6_addr& addr) { + char buf[INET6_ADDRSTRLEN]; + if (inet_ntop(AF_INET6, &addr, buf, sizeof(buf)) == nullptr) { + return "[unknown]"; + } + return buf; +} + +Address::Address() { + mStorage.reserve(sizeof(struct sockaddr_storage)); +} + +Address::Address(const struct sockaddr_nl& address) + : mStorage(sizeof(address)) { + memcpy(mStorage.data(), &address, sizeof(address)); +} +Address::Address(const struct sockaddr_in6& address) + : mStorage(sizeof(address)) { + memcpy(mStorage.data(), &address, sizeof(address)); +} + +Address::Address(struct in6_addr address) + : mStorage(sizeof(struct sockaddr_in6)) { + auto sockaddr = reinterpret_cast<struct sockaddr_in6*>(mStorage.data()); + sockaddr->sin6_family = AF_INET6; + sockaddr->sin6_addr = address; +} + +void Address::reset() { + mStorage.resize(sizeof(struct sockaddr_storage)); +} + +Result Address::resolveInet(const std::string& address) { + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_RAW; + struct addrinfo* addrinfo; + int res = ::getaddrinfo(address.c_str(), nullptr, &hints, &addrinfo); + if (res != 0) { + return Result::error(gai_strerror(res)); + } + mStorage.resize(addrinfo->ai_addrlen); + memcpy(mStorage.data(), addrinfo->ai_addr, mStorage.size()); + freeaddrinfo(addrinfo); + + return Result::success(); +} + +Result Address::resolveEth(const std::string& interfaceName) { + mStorage.resize(sizeof(struct sockaddr_ll)); + memset(mStorage.data(), 0, mStorage.size()); + auto addr = reinterpret_cast<struct sockaddr_ll*>(mStorage.data()); + addr->sll_family = AF_PACKET; + addr->sll_protocol = htons(ETH_P_IPV6); + + unsigned int index = if_nametoindex(interfaceName.c_str()); + if (index == 0) { + return Result::error(strerror(errno)); + } + addr->sll_ifindex = index; + + struct ifreq request; + memset(&request, 0, sizeof(request)); + strncpy(request.ifr_name, interfaceName.c_str(), sizeof(request.ifr_name)); + request.ifr_name[sizeof(request.ifr_name) - 1] = '\0'; + + Socket socket; + Result res = socket.open(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (!res) { + return res; + } + int status = ::ioctl(socket.get(), SIOCGIFHWADDR, &request); + if (status != 0) { + return Result::error(strerror(errno)); + } + memcpy(addr->sll_addr, request.ifr_addr.sa_data, 6); + + return Result::success(); +} diff --git a/wifi/ipv6proxy/address.h b/wifi/ipv6proxy/address.h new file mode 100644 index 00000000..f9cec0bd --- /dev/null +++ b/wifi/ipv6proxy/address.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "result.h" + +#include <linux/netlink.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <string> +#include <vector> + +// Convert an IPv6 address struct to a string for debugging purposes +std::string addrToStr(const struct in6_addr& addr); + +// Represents any kind of address in a struct sockaddr. +class Address { +public: + Address(); + explicit Address(const struct sockaddr_nl& address); + explicit Address(const struct sockaddr_in6& address); + explicit Address(struct in6_addr address); + + template<typename T> + const T* get() const { + return reinterpret_cast<const T*>(mStorage.data()); + } + + template<typename T> + T* get() { + return reinterpret_cast<T*>(mStorage.data()); + } + + ssize_t size() const { return mStorage.size(); } + + // Reset the address to be the max size possible for an address + void reset(); + + // Resolve |address| into an IPv6 address. |address| may be either a domain + // name or just a string containing a numeric address. + Result resolveInet(const std::string& address); + // Resolve |interfaceName| into a link layer address. This can be used to + // create a struct sockaddr_nl that can be used to listen on the given + // interface at the link layer. + Result resolveEth(const std::string& interfaceName); +private: + std::vector<char> mStorage; +}; + diff --git a/wifi/ipv6proxy/interface.cpp b/wifi/ipv6proxy/interface.cpp new file mode 100644 index 00000000..e9597ab5 --- /dev/null +++ b/wifi/ipv6proxy/interface.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "interface.h" + +#include <errno.h> +#include <linux/if_ether.h> +#include <net/if.h> +#include <string.h> +#include <sys/ioctl.h> + +#include "log.h" + +Interface::Interface(const std::string& name) : mName(name) { +} + +bool Interface::init() { + // setAllMulti will set the ALLMULTI flag for the interface, this allows us + // to capture all the traffic needed to perform proxying. + return setAllMulti() && + resolveAddresses() && + configureIpSocket() && + configureIcmpSocket(); +} + +bool Interface::setAllMulti() { + struct ifreq request; + memset(&request, 0, sizeof(request)); + strncpy(request.ifr_name, mName.c_str(), sizeof(request.ifr_name)); + request.ifr_name[sizeof(request.ifr_name) - 1] = '\0'; + + Socket socket; + Result res = socket.open(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (!res) { + loge("Failed to open IP socket for interface %s: %s\n", + mName.c_str(), strerror(errno)); + return false; + } + int status = ::ioctl(socket.get(), SIOCGIFFLAGS, &request); + if (status != 0) { + loge("Failed to get interface flags for %s: %s\n", + mName.c_str(), strerror(errno)); + return false; + } + + if ((request.ifr_flags & IFF_ALLMULTI) != 0) { + // AllMulti is already enabled, nothing to do + return true; + } + + request.ifr_flags |= IFF_ALLMULTI; + + status = ::ioctl(socket.get(), SIOCSIFFLAGS, &request); + if (status != 0) { + loge("Failed to enable AllMulti flag for %s: %s\n", + mName.c_str(), strerror(errno)); + return false; + } + return true; +} + +bool Interface::resolveAddresses() { + Result res = mLinkAddr.resolveEth(mName); + if (!res) { + loge("Unable to resolve interface %s: %s\n", + mName.c_str(), res.c_str()); + return false; + } + mIndex = if_nametoindex(mName.c_str()); + if (mIndex == 0) { + loge("Unable to get interface index for '%s': %s\n", + mName.c_str(), strerror(errno)); + return false; + } + return true; +} + +bool Interface::configureIcmpSocket() { + Result res = mIcmpSocket.open(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + if (!res) { + loge("Error opening socket: %s\n", res.c_str()); + return false; + } + + // The ICMP messages we are going to send need a hop limit of 255 to be + // accepted. + res = mIcmpSocket.setMulticastHopLimit(255); + if (!res) { + loge("Error setting socket hop limit: %s\n", res.c_str()); + return false; + } + res = mIcmpSocket.setUnicastHopLimit(255); + if (!res) { + loge("Error setting socket hop limit: %s\n", res.c_str()); + return false; + } + + // We only care about one specific interface + res = mIcmpSocket.setInterface(mName); + if (!res) { + loge("Error socket interface: %s\n", res.c_str()); + return false; + } + + // Make sure the socket allows transparent proxying, this allows sending of + // packets with a source address that is different from the interface. + res = mIcmpSocket.setTransparent(true); + if (!res) { + loge("Error socket interface: %s\n", res.c_str()); + return false; + } + + return true; +} + +bool Interface::configureIpSocket() { + Result res = mIpSocket.open(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6); + if (!res) { + loge("Error opening socket: %s\n", res.c_str()); + return false; + } + + res = mIpSocket.bind(mLinkAddr); + if (!res) { + loge("Error binding socket: %s\n", res.c_str()); + return false; + } + return true; +} + diff --git a/wifi/ipv6proxy/interface.h b/wifi/ipv6proxy/interface.h new file mode 100644 index 00000000..e6e5d78a --- /dev/null +++ b/wifi/ipv6proxy/interface.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <stdint.h> +#include <string> + +#include "address.h" +#include "socket.h" + +// A class that contains the information used by the proxy that is specific to a +// single interface. This includes the name and index of the interface as well +// as the sockets used to send and receive data on the interface. +// +// The class also contains the functionality needed to initialized and configure +// the interface, sockets and addresses. +class Interface { +public: + explicit Interface(const std::string& name); + + bool init(); + + const std::string& name() const { return mName; } + uint32_t index() const { return mIndex; } + Socket& ipSocket() { return mIpSocket; } + Socket& icmpSocket() { return mIcmpSocket; } + const Address& linkAddr() const { return mLinkAddr; } + +private: + bool setAllMulti(); + bool resolveAddresses(); + bool configureIcmpSocket(); + bool configureIpSocket(); + + std::string mName; + uint32_t mIndex; + Socket mIpSocket; + Socket mIcmpSocket; + Address mLinkAddr; +}; + diff --git a/wifi/ipv6proxy/log.cpp b/wifi/ipv6proxy/log.cpp new file mode 100644 index 00000000..a23b0621 --- /dev/null +++ b/wifi/ipv6proxy/log.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "log.h" + +#ifndef ANDROID +#include <stdarg.h> +#ifdef USE_LOG_TIMESTAMPS +#include <time.h> +#endif // USE_LOG_TIMESTAMPS + +static void vlogf(FILE* stream, const char* fmt, va_list args) { +#ifdef USE_LOG_TIMESTAMPS + struct timespec ts; + struct tm localTime; + static bool newLine = true; + if (newLine && clock_gettime(CLOCK_REALTIME, &ts) == 0) { + time_t now = ts.tv_sec; + if (localtime_r(&now, &localTime)) { + char format[32]; + char timestamp[1024]; + snprintf(format, sizeof(format), "[%%T.%03lld] ", (long long)(ts.tv_nsec) / 1000000); + strftime(timestamp, sizeof(timestamp), format, &localTime); + fprintf(stream, "%s ", timestamp); + } + } + newLine = (fmt[strlen(fmt) - 1] == '\n'); +#endif // USE_LOG_TIMESTAMPS + vfprintf(stream, fmt, args); +} + +static void logf(FILE* stream, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vlogf(stream, fmt, args); + va_end(args); +} + +void loge(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vlogf(stderr, fmt, args); + va_end(args); +} + +void logd(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vlogf(stdout, fmt, args); + va_end(args); +} +#endif // !ANDROID diff --git a/wifi/ipv6proxy/log.h b/wifi/ipv6proxy/log.h new file mode 100644 index 00000000..53e89350 --- /dev/null +++ b/wifi/ipv6proxy/log.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#ifdef ANDROID + +#define LOG_TAG "ipv6proxy" +#include <log/log.h> + +#define loge(...) ALOGE(__VA_ARGS__) +#define logd(...) ALOGD(__VA_ARGS__) + +#else +#include <stdio.h> + +void loge(const char* fmt, ...); +void logd(const char* fmt, ...); + +#endif diff --git a/wifi/ipv6proxy/main.cpp b/wifi/ipv6proxy/main.cpp new file mode 100644 index 00000000..91445caf --- /dev/null +++ b/wifi/ipv6proxy/main.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vector> + +#include <string.h> + +#include "log.h" +#include "namespace.h" +#include "proxy.h" + +void usage(const char* program) { + loge("Usage: %s -n [namespace|pid] -o <outer if> -i <inner ifs>\n", + program); + loge(" -o Outer interface that connects to an existing IPv6 network.\n" + " -i Comma separated list of inner interfaces that would like\n" + " to access the IPv6 network available on the outer interface.\n" + " -n Optional parameter that causes the proxy to run in the given\n" + " network namespace. If a name is given instead of a PID the\n" + " namespace is expected to be set up by iproute2 or with a\n" + " similar approach where the namespace is linked in\n" + " /var/run/netns. A PID is assumed if the argument is numeric.\n" + " If providing a PID the same namespace that the PID is\n" + " running in will be used. In this scenario there is no\n" + " requirement for a file in /var/run/netns.\n" + "\n" + " The proxy will ensure that router solicitations from inner\n" + " interfaces are forwarded to the outer interface and that\n" + " router advertisements from the outer interface are forwarded\n" + " to the inner interfaces. In addition to this neighbor\n" + " solicitations and advertisements will also be forwarded in a\n" + " way that enables IPv6 connectivity and routes will be set up\n" + " for source addresses on the inner interfaces so that replies\n" + " can reach those sources as expected.\n" + ); +} + +static std::vector<const char*> splitString(char* str, char delimiter) { + std::vector<const char*> parts; + char* part = nullptr; + do { + parts.push_back(str); + part = strchr(str, delimiter); + if (part != nullptr) { + *part = '\0'; + str = part + 1; + } + } while (part != nullptr); + return parts; +} + +int main(int argc, char* argv[]) { + char* inner = nullptr; + const char* outer = nullptr; + const char* netNamespace = nullptr; + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "-o") == 0) { + outer = argv[++i]; + } else if (strcmp(argv[i], "-i") == 0) { + inner = argv[++i]; + } else if (strcmp(argv[i], "-h") == 0 || + strcmp(argv[i], "--help") == 0) { + usage(argv[0]); + return 1; + } else if (strcmp(argv[i], "-n") == 0) { + netNamespace = argv[++i]; + } else { + loge("ERROR: Unknown argument '%s'\n\n", argv[i]); + usage(argv[0]); + return 1; + } + } + bool error = false; + if (inner == nullptr) { + loge("ERROR: Missing inner interface\n"); + error = true; + } + if (outer == nullptr) { + loge("ERROR: Missing outer interface\n"); + error = true; + } + if (netNamespace) { + if (!setNetworkNamespace(netNamespace)) { + error = true; + } + } + if (error) { + usage(argv[0]); + return 1; + } + + std::vector<const char*> innerInterfaces = splitString(inner, ','); + + Proxy proxy(outer, innerInterfaces.begin(), innerInterfaces.end()); + + return proxy.run(); +} + diff --git a/wifi/ipv6proxy/message.h b/wifi/ipv6proxy/message.h new file mode 100644 index 00000000..9b35daeb --- /dev/null +++ b/wifi/ipv6proxy/message.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +class Message { +public: + + size_t size() const { return mSize; } + size_t capacity() const { return sizeof(mData); } + const char* data() const { return mData; } + char* data() { return mData; } + + void setSize(size_t size) { mSize = size; } + +protected: + char mData[8192]; + size_t mSize; +}; + diff --git a/wifi/ipv6proxy/namespace.cpp b/wifi/ipv6proxy/namespace.cpp new file mode 100644 index 00000000..04841c29 --- /dev/null +++ b/wifi/ipv6proxy/namespace.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "namespace.h" + +#include <errno.h> +#include <fcntl.h> +#include <linux/limits.h> +#include <sched.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "log.h" + +static const char kNetNsDir[] = "/data/vendor/var/run/netns"; + +// Set the current namespace to that of the /proc/<pid>/ns/net provided in +// |path|. This may be a link or mount point for that same file, anything that +// when opened will be an fd usable by setns is fine. +static bool setNamespaceFromPath(const char* path) { + int nsFd = open(path, O_RDONLY | O_CLOEXEC); + if (nsFd == -1) { + loge("Cannot open network namespace at '%s': %s\n", + path, strerror(errno)); + return false; + } + + if (setns(nsFd, CLONE_NEWNET) == -1) { + loge("Cannot set network namespace at '%s': %s\n", + path, strerror(errno)); + close(nsFd); + return false; + } + close(nsFd); + return true; +} + +bool setNetworkNamespace(const char* ns) { + // There is a file in the net namespace dir (usually /var/run/netns) with + // the same name as the namespace. This file is bound to /proc/<pid>/ns/net + // by the 'ip' command when the namespace is created. This allows us to + // access the file of a process running in that network namespace without + // knowing its pid, knowing the namespace name is enough. + // + // We are going to call setns which requires a file descriptor to that proc + // file in /proc/<pid>/net. The process has to already be running in that + // namespace. Since the file in the net namespace dir has been bound to + // such a file already we just have to open /var/run/netns/<namespace> and + // we have the required file descriptor. + char nsPath[PATH_MAX]; + snprintf(nsPath, sizeof(nsPath), "%s/%s", kNetNsDir, ns); + return setNamespaceFromPath(nsPath); +} + +bool setNetworkNamespace(pid_t pid) { + // If we know the pid we can create the path to the /proc file right away + // and use that when we call setns. + char nsPath[PATH_MAX]; + static_assert(sizeof(pid_t) <= sizeof(unsigned long long), + "Cast requires sizeof(pid_t) <= sizeof(unsigned long long)"); + snprintf(nsPath, sizeof(nsPath), "/proc/%llu/ns/net/", + static_cast<unsigned long long>(pid)); + return setNamespaceFromPath(nsPath); +} + diff --git a/network/wifi_forwarder/hash.h b/wifi/ipv6proxy/namespace.h index ecd8c23a..8a703741 100644 --- a/network/wifi_forwarder/hash.h +++ b/wifi/ipv6proxy/namespace.h @@ -1,5 +1,5 @@ /* - * Copyright 2019, The Android Open Source Project + * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #pragma once -#include <functional> +#include <sys/types.h> -template<class T> -inline void hash_combine(size_t& seed, const T& value) { - std::hash<T> hasher; - seed ^= hasher(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2); -} +// Move the process into the namespace |ns| +bool setNetworkNamespace(const char* ns); +// Move the process into the same namespace as the process |pid| is in. +bool setNetworkNamespace(pid_t pid); diff --git a/wifi/ipv6proxy/packet.cpp b/wifi/ipv6proxy/packet.cpp new file mode 100644 index 00000000..fa15a758 --- /dev/null +++ b/wifi/ipv6proxy/packet.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "packet.h" + +#include "address.h" + +Packet::Packet(Message& message) + : mMessage(message), + mType(Type::Other), + mIp(nullptr), + mIcmp(nullptr), + mFirstOpt(nullptr) { + if (message.size() < sizeof(ip6_hdr) + sizeof(icmp6_hdr)) { + mType = Type::Other; + return; + } + mIp = reinterpret_cast<const ip6_hdr*>(message.data()); + uint8_t version = (mIp->ip6_vfc & 0xF0) >> 4; + if (version != 6 || mIp->ip6_nxt != IPPROTO_ICMPV6) { + mType = Type::Other; + return; + } + + size_t size = message.size() - sizeof(ip6_hdr); + char* data = message.data() + sizeof(ip6_hdr); + mIcmp = reinterpret_cast<const icmp6_hdr*>(data); + if (mIcmp->icmp6_code != 0) { + // All messages we care about have a code of zero + mType = Type::Other; + return; + } + + size_t headerSize = 0; + switch (mIcmp->icmp6_type) { + case ND_ROUTER_SOLICIT: + headerSize = sizeof(nd_router_solicit); + mType = Type::RouterSolicitation; + break; + case ND_ROUTER_ADVERT: + headerSize = sizeof(nd_router_advert); + mType = Type::RouterAdvertisement; + break; + case ND_NEIGHBOR_SOLICIT: + headerSize = sizeof(nd_neighbor_solicit); + mType = Type::NeighborSolicitation; + break; + case ND_NEIGHBOR_ADVERT: + headerSize = sizeof(nd_neighbor_advert); + mType = Type::NeighborAdvertisement; + break; + default: + mType = Type::Other; + return; + } + if (size < headerSize) { + mType = Type::Other; + return; + } + + // We might have options + char* options = data + headerSize; + if (options + sizeof(nd_opt_hdr) < data + size) { + nd_opt_hdr* option = reinterpret_cast<nd_opt_hdr*>(options); + // Option length is in units of 8 bytes, multiply by 8 to get bytes + if (options + option->nd_opt_len * 8u <= data + size) { + mFirstOpt = option; + } + } +} + +std::string Packet::description() const { + char buffer[256]; + switch (mType) { + case Type::NeighborSolicitation: { + auto ns = reinterpret_cast<const nd_neighbor_solicit*>(icmp()); + snprintf(buffer, sizeof(buffer), "Neighbor Solicitation for %s", + addrToStr(ns->nd_ns_target).c_str()); + return buffer; + } + case Type::NeighborAdvertisement: { + auto na = reinterpret_cast<const nd_neighbor_advert*>(icmp()); + snprintf(buffer, sizeof(buffer), + "Neighbor Advertisement for %s", + addrToStr(na->nd_na_target).c_str()); + return buffer; + } + case Type::RouterSolicitation: + return "Router Solicitation"; + case Type::RouterAdvertisement: + return "Router Advertisement"; + default: + break; + } + return "[unknown]"; +} + +nd_opt_hdr* Packet::firstOpt() { + return mFirstOpt; +} + +nd_opt_hdr* Packet::nextOpt(nd_opt_hdr* currentHeader) { + char* end = mMessage.data() + mMessage.size(); + char* current = reinterpret_cast<char*>(currentHeader); + if (currentHeader < mFirstOpt || current >= end) { + // The provided header does not belong to this packet info. + return nullptr; + } + char* next = current + currentHeader->nd_opt_len * 8u; + if (next >= end) { + // The next header points passed the message data + return nullptr; + } + nd_opt_hdr* nextHeader = reinterpret_cast<nd_opt_hdr*>(next); + if (next + nextHeader->nd_opt_len * 8u > end) { + // The next option extends beyond the message data + return nullptr; + } + return nextHeader; +} + diff --git a/wifi/ipv6proxy/packet.h b/wifi/ipv6proxy/packet.h new file mode 100644 index 00000000..49e69d4c --- /dev/null +++ b/wifi/ipv6proxy/packet.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <netinet/icmp6.h> +#include <netinet/ip6.h> + +#include <string> +#include <vector> + +#include "message.h" + +class Packet { +public: + enum class Type { + NeighborSolicitation, + NeighborAdvertisement, + RouterSolicitation, + RouterAdvertisement, + Other + }; + + explicit Packet(Message& message); + + // Create a string that can be used for debug purposes to describe + // what type of packet and potentially its target for certain types. + std::string description() const; + + // Full size including IP header + size_t fullSize() const { + return mMessage.size(); + } + // Remaining size including ICMPv6 header but excluding IP header + size_t icmpSize() const { + return mMessage.size() - sizeof(ip6_hdr); + } + + Type type() const { + return mType; + } + const ip6_hdr* ip() const { + return mIp; + } + const icmp6_hdr* icmp() const { + return mIcmp; + } + + nd_opt_hdr* firstOpt(); + nd_opt_hdr* nextOpt(nd_opt_hdr* currentHeader); + +private: + Message& mMessage; + Type mType; + + const ip6_hdr* mIp; + const icmp6_hdr* mIcmp; + nd_opt_hdr* mFirstOpt; +}; + diff --git a/wifi/ipv6proxy/proxy.cpp b/wifi/ipv6proxy/proxy.cpp new file mode 100644 index 00000000..cb19ff7d --- /dev/null +++ b/wifi/ipv6proxy/proxy.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "proxy.h" + +#include <arpa/inet.h> +#include <errno.h> +#include <linux/if_packet.h> +#include <poll.h> +#include <signal.h> + +#include <cutils/properties.h> + +#include "log.h" +#include "message.h" +#include "packet.h" +#include "result.h" + +// The prefix length for an address of a single unique node +static const uint8_t kNodePrefixLength = 128; +static const size_t kLinkAddressSize = 6; +static const size_t kRecursiveDnsOptHeaderSize = 8; + +// Rewrite the link address of a neighbor discovery option to the link address +// of |interface|. This can be either a source or target link address as +// specified by |optionType|. The valid values are ND_OPT_TARGET_LINKADDR and +// ND_OPT_SOURCE_LINKADDR. This will modify the message data inside |packet|. +static void rewriteLinkAddressOption(Packet& packet, + const Interface& interface, + int optionType) { + for (nd_opt_hdr* opt = packet.firstOpt(); opt; opt = packet.nextOpt(opt)) { + if (opt->nd_opt_type == optionType) { + auto src = interface.linkAddr().get<sockaddr_ll>(); + auto dest = reinterpret_cast<char*>(opt) + sizeof(nd_opt_hdr); + memcpy(dest, src->sll_addr, kLinkAddressSize); + } + } +} + +static void extractRecursiveDnsServers(Packet& packet) { + for (nd_opt_hdr* opt = packet.firstOpt(); opt; opt = packet.nextOpt(opt)) { + if (opt->nd_opt_type != 25 || opt->nd_opt_len < 1) { + // Not a RNDSS option, skip it + continue; + } + size_t numEntries = (opt->nd_opt_len - 1) / 2; + //Found number of entries, dump each address + const char* option = reinterpret_cast<const char*>(opt); + option += kRecursiveDnsOptHeaderSize; + auto dnsServers = reinterpret_cast<const struct in6_addr*>(option); + + std::vector<std::string> validServers; + for (size_t i = 0; i < numEntries; ++i) { + char buffer[INET6_ADDRSTRLEN]; + if (inet_ntop(AF_INET6, &dnsServers[i], buffer, sizeof(buffer))) { + validServers.push_back(buffer); + } else { + loge("Failed to convert RDNSS to string\n"); + } + } + + auto server = validServers.begin(); + char propName[PROP_NAME_MAX]; + char propValue[PROP_VALUE_MAX]; + for (int i = 1; i <= 4; ++i) { + snprintf(propName, sizeof(propName), "net.eth0.ipv6dns%d", i); + if (server != validServers.end()) { + property_set(propName, server->c_str()); + ++server; + } else { + // Clear the property if it's no longer a valid server, don't + // want to leave old servers around + property_set(propName, ""); + } + } + } +} + +int Proxy::run() { + sigset_t blockMask, originalMask; + int status = ::sigfillset(&blockMask); + if (status != 0) { + loge("Unable to fill signal set: %s\n", strerror(errno)); + return 1; + } + status = ::sigprocmask(SIG_SETMASK, &blockMask, &originalMask); + if (status != 0) { + loge("Unable to set signal mask: %s\n", strerror(errno)); + return 1; + } + // Init outer interface and router + if (!mOuterIf.init() || !mRouter.init()) { + return 1; + } + // Init all inner interfaces + for (size_t i = 0; i < mInnerIfs.size(); ++i) { + if (!mInnerIfs[i].init()) { + return 1; + } + } + + // Create list of FDs to poll, we're only looking for input (POLLIN) + std::vector<pollfd> fds(mInnerIfs.size() + 1); + fds[0].fd = mOuterIf.ipSocket().get(); + fds[0].events = POLLIN; + for (size_t i = 0; i < mInnerIfs.size(); ++i) { + fds[i + 1].fd = mInnerIfs[i].ipSocket().get(); + fds[i + 1].events = POLLIN; + } + + Message message; + while (status >= 0) { + status = ::ppoll(fds.data(), fds.size(), nullptr, &originalMask); + if (status > 0) { + // Something available to read + for (const struct pollfd& fd : fds) { + if (receiveIfPossible(fd, mOuterIf.ipSocket(), &message)) { + // Received a message on the outer interface + handleOuterMessage(message); + } else { + for (auto& inner : mInnerIfs) { + if (receiveIfPossible(fd, inner.ipSocket(), &message)) { + // Received a message on the inner interface + handleInnerMessage(inner, message); + } + } + } + } + } + } + loge("Polling failed: %s\n", strerror(errno)); + return 1; +} + +bool Proxy::receiveIfPossible(const pollfd& fd, + Socket& socket, + Message* message) { + // Check if it's actually the socket we're interested in + if (fd.fd != socket.get()) { + return false; + } + // Check if there is something to read on this socket + if ((fd.revents & POLLIN) == 0) { + return false; + } + + // Receive the message and place the data in the message parameter + Result res = socket.receive(message); + if (!res) { + loge("Error receiving on socket: %s\n", res.c_str()); + return false; + } + return true; +} + +void Proxy::handleOuterMessage(Message& message) { + Packet packet(message); + uint32_t options = kForwardOnly; + switch (packet.type()) { + case Packet::Type::RouterAdvertisement: + extractRecursiveDnsServers(packet); + options = kRewriteSourceLink | kSetDefaultGateway; + break; + case Packet::Type::NeighborSolicitation: + options = kSpoofSource; + break; + case Packet::Type::NeighborAdvertisement: + options = kRewriteTargetLink; + break; + default: + return; + } + for (auto& inner : mInnerIfs) { + forward(mOuterIf, inner, packet, options); + } +} + +void Proxy::handleInnerMessage(const Interface& inner, Message& message) { + Packet packet(message); + uint32_t options = kForwardOnly; + switch (packet.type()) { + case Packet::Type::RouterSolicitation: + options = kSpoofSource; + break; + case Packet::Type::NeighborSolicitation: + options = kSpoofSource | kAddRoute; + break; + case Packet::Type::NeighborAdvertisement: + options = kRewriteTargetLink | kSpoofSource | kAddRoute; + break; + default: + return; + } + forward(inner, mOuterIf, packet, options); +} + +void Proxy::forward(const Interface& from, + Interface& to, + Packet& packet, + uint32_t options) { + if (mLogDebug) { + logd("Forwarding %s from %s/%s to %s/%s\n", + packet.description().c_str(), + from.name().c_str(), addrToStr(packet.ip()->ip6_src).c_str(), + to.name().c_str(), addrToStr(packet.ip()->ip6_dst).c_str()); + } + + if (options & kRewriteTargetLink) { + rewriteLinkAddressOption(packet, to, ND_OPT_TARGET_LINKADDR); + } + if (options & kRewriteSourceLink) { + rewriteLinkAddressOption(packet, to, ND_OPT_SOURCE_LINKADDR); + } + + Result res = Result::success(); + if (options & kSpoofSource) { + // Spoof the source of the packet so that it appears to originate from + // the same source that we see. + res = to.icmpSocket().sendFrom(packet.ip()->ip6_src, + packet.ip()->ip6_dst, + packet.icmp(), + packet.icmpSize()); + } else { + res = to.icmpSocket().sendTo(packet.ip()->ip6_dst, + packet.icmp(), + packet.icmpSize()); + } + if (!res) { + loge("Failed to forward %s from %s to %s: %s\n", + packet.description().c_str(), + from.name().c_str(), to.name().c_str(), + res.c_str()); + } + + if (options & kAddRoute) { + mRouter.addRoute(packet.ip()->ip6_src, kNodePrefixLength, from.index()); + } + if (packet.type() == Packet::Type::RouterAdvertisement && + options & kSetDefaultGateway) { + // Set the default gateway from this router advertisement. This is + // needed so that packets that are forwarded as a result of proxying + // actually have somewhere to go. + if (!mRouter.setDefaultGateway(packet.ip()->ip6_src, from.index())) { + loge("Failed to set default gateway %s\n", + addrToStr(packet.ip()->ip6_src).c_str()); + } + } +} + diff --git a/wifi/ipv6proxy/proxy.h b/wifi/ipv6proxy/proxy.h new file mode 100644 index 00000000..51791373 --- /dev/null +++ b/wifi/ipv6proxy/proxy.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <string> +#include <vector> + +#include "interface.h" +#include "router.h" + +struct pollfd; +class Message; +class Packet; +class Socket; + +class Proxy { +public: + template<typename Iter> + Proxy(std::string outerInterfaceName, + Iter innerInterfacesBegin, Iter innerInterfacesEnd) + : mOuterIf(outerInterfaceName), + mLogDebug(false) { + + for (Iter i = innerInterfacesBegin; i != innerInterfacesEnd; ++i) { + mInnerIfs.emplace_back(*i); + } + } + + int run(); + +private: + enum ForwardOpt { + kForwardOnly = 0, + kRewriteTargetLink = (1 << 0), + kRewriteSourceLink = (1 << 1), + kSpoofSource = (1 << 2), + kAddRoute = (1 << 3), + kSetDefaultGateway = (1 << 4) + }; + + bool receiveIfPossible(const pollfd&, Socket& socket, Message* message); + + void handleOuterMessage(Message& message); + void handleInnerMessage(const Interface& inner, Message& message); + void forward(const Interface& from, Interface& to, + Packet& packet, uint32_t options); + + std::vector<Interface> mInnerIfs; + Interface mOuterIf; + + Router mRouter; + bool mLogDebug; +}; + diff --git a/network/wifi_forwarder/result.h b/wifi/ipv6proxy/result.h index 5087e146..5cd2b035 100644 --- a/network/wifi_forwarder/result.h +++ b/wifi/ipv6proxy/result.h @@ -15,40 +15,28 @@ */ #pragma once -#include <stdio.h> -#include <stdarg.h> - -#include <string> - class Result { public: static Result success() { return Result(true); } - // Construct a result indicating an error. - static Result error(std::string message) { + // Construct a result indicating an error. NOTE: the data in |message| will + // NOT be copied. It must be kept alive for as long as its intended to be + // used. This way the object is kept light-weight. + static Result error(const char* message) { return Result(message); } - static Result error(const char* format, ...) { - char buffer[1024]; - va_list args; - va_start(args, format); - vsnprintf(buffer, sizeof(buffer), format, args); - va_end(args); - buffer[sizeof(buffer) - 1] = '\0'; - return Result(std::string(buffer)); - } bool isSuccess() const { return mSuccess; } bool operator!() const { return !mSuccess; } - const char* c_str() const { return mMessage.c_str(); } + const char* c_str() const { return mMessage; } private: explicit Result(bool success) : mSuccess(success) { } - explicit Result(std::string message) + explicit Result(const char* message) : mMessage(message), mSuccess(false) { } - std::string mMessage; + const char* mMessage; bool mSuccess; }; diff --git a/wifi/ipv6proxy/router.cpp b/wifi/ipv6proxy/router.cpp new file mode 100644 index 00000000..be505c92 --- /dev/null +++ b/wifi/ipv6proxy/router.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "router.h" + +#include <linux/rtnetlink.h> +#include <stddef.h> +#include <string.h> + +#include "address.h" +#include "log.h" + +template<class Request> +static void addRouterAttribute(Request& r, + int type, + const void* data, + size_t size) { + // Calculate the offset into the character buffer where the RTA data lives + // We use offsetof on the buffer to get it. This avoids undefined behavior + // by casting the buffer (which is safe because it's char) instead of the + // Request struct.(which is undefined because of aliasing) + size_t offset = NLMSG_ALIGN(r.hdr.nlmsg_len) - offsetof(Request, buf); + auto attr = reinterpret_cast<struct rtattr*>(r.buf + offset); + attr->rta_type = type; + attr->rta_len = RTA_LENGTH(size); + memcpy(RTA_DATA(attr), data, size); + + // Update the message length to include the router attribute. + r.hdr.nlmsg_len = NLMSG_ALIGN(r.hdr.nlmsg_len) + RTA_ALIGN(attr->rta_len); +} + +bool Router::init() { + // Create a netlink socket to the router + Result res = mSocket.open(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (!res) { + loge("Unable to open netlink socket: %s\n", res.c_str()); + return false; + } + return true; +} + +bool Router::addNeighbor(const struct in6_addr& address, + unsigned int interfaceIndex) { + struct Request { + struct nlmsghdr hdr; + struct ndmsg msg; + char buf[256]; + } request; + + memset(&request, 0, sizeof(request)); + + unsigned short msgLen = NLMSG_LENGTH(sizeof(request.msg)); + // Set up a request to create a new neighbor + request.hdr.nlmsg_len = msgLen; + request.hdr.nlmsg_type = RTM_NEWNEIGH; + request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; + + // The neighbor is a permanent IPv6 proxy + request.msg.ndm_family = AF_INET6; + request.msg.ndm_state = NUD_PERMANENT; + request.msg.ndm_flags = NTF_PROXY; + request.msg.ndm_ifindex = interfaceIndex; + + addRouterAttribute(request, NDA_DST, &address, sizeof(address)); + + return sendNetlinkMessage(&request, request.hdr.nlmsg_len); +} + +bool Router::addRoute(const struct in6_addr& address, + uint8_t bits, + uint32_t ifaceIndex) { + struct Request { + struct nlmsghdr hdr; + struct rtmsg msg; + char buf[256]; + } request; + + memset(&request, 0, sizeof(request)); + + // Set up a request to create a new route + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg)); + request.hdr.nlmsg_type = RTM_NEWROUTE; + request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; + + request.msg.rtm_family = AF_INET6; + request.msg.rtm_dst_len = bits; + request.msg.rtm_table = RT_TABLE_MAIN; + request.msg.rtm_protocol = RTPROT_RA; + request.msg.rtm_scope = RT_SCOPE_UNIVERSE; + request.msg.rtm_type = RTN_UNICAST; + + addRouterAttribute(request, RTA_DST, &address, sizeof(address)); + addRouterAttribute(request, RTA_OIF, &ifaceIndex, sizeof(ifaceIndex)); + + return sendNetlinkMessage(&request, request.hdr.nlmsg_len); +} + +bool Router::setDefaultGateway(const struct in6_addr& address, + unsigned int ifaceIndex) { + struct Request { + struct nlmsghdr hdr; + struct rtmsg msg; + char buf[256]; + } request; + + memset(&request, 0, sizeof(request)); + + // Set up a request to create a new route + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg)); + request.hdr.nlmsg_type = RTM_NEWROUTE; + request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; + + request.msg.rtm_family = AF_INET6; + request.msg.rtm_dst_len = 0; + request.msg.rtm_src_len = 0; + request.msg.rtm_table = RT_TABLE_MAIN; + request.msg.rtm_protocol = RTPROT_RA; + request.msg.rtm_scope = RT_SCOPE_UNIVERSE; + request.msg.rtm_type = RTN_UNICAST; + + struct in6_addr anyAddress; + memset(&anyAddress, 0, sizeof(anyAddress)); + addRouterAttribute(request, RTA_GATEWAY, &address, sizeof(address)); + addRouterAttribute(request, RTA_OIF, &ifaceIndex, sizeof(ifaceIndex)); + addRouterAttribute(request, RTA_SRC, &anyAddress, sizeof(anyAddress)); + + return sendNetlinkMessage(&request, request.hdr.nlmsg_len); +} + +bool Router::sendNetlinkMessage(const void* data, size_t size) { + struct sockaddr_nl netlinkAddress; + memset(&netlinkAddress, 0, sizeof(netlinkAddress)); + netlinkAddress.nl_family = AF_NETLINK; + Result res = mSocket.sendTo(netlinkAddress, data, size); + if (!res) { + loge("Unable to send on netlink socket: %s\n", res.c_str()); + return false; + } + return true; +} + diff --git a/wifi/ipv6proxy/router.h b/wifi/ipv6proxy/router.h new file mode 100644 index 00000000..66e896ff --- /dev/null +++ b/wifi/ipv6proxy/router.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <stdint.h> + +#include <netinet/in.h> + +#include "socket.h" + +class Router { +public: + // Initialize the router, this has to be called before any other methods can + // be called. It only needs to be called once. + bool init(); + + // Indicate that |address| is a neighbor to this node and that it is + // accessible on the interface with index |interfaceIndex|. + bool addNeighbor(const struct in6_addr& address, uint32_t interfaceIndex); + + // Add a route to |address|/|bits| on interface |interfaceIndex|. The + // |bits| parameter indicates the bitmask of the address, for example in + // the routing entry 2001:db8::/32 the |bits| parameter would be 32. + bool addRoute(const struct in6_addr& address, + uint8_t bits, + uint32_t interfaceIndex); + + // Set the default gateway route to |address| on interface with index + // |interfaceIndex|. Overwrites any existing default gateway with the same + // address. + bool setDefaultGateway(const struct in6_addr& address, + unsigned int interfaceIndex); +private: + bool sendNetlinkMessage(const void* data, size_t size); + + // Netlink socket for setting up neighbors and routes + Socket mSocket; +}; + diff --git a/wifi/ipv6proxy/socket.cpp b/wifi/ipv6proxy/socket.cpp new file mode 100644 index 00000000..3b678161 --- /dev/null +++ b/wifi/ipv6proxy/socket.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "socket.h" + +#include <errno.h> +#include <string.h> + +#include <linux/in6.h> +#include <net/ethernet.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "address.h" +#include "message.h" + +Socket::Socket() : mState(State::New), mSocket(-1) { +} + +Socket::Socket(Socket&& other) noexcept : mState(other.mState), mSocket(other.mSocket) { + other.mSocket = -1; + other.mState = State::Moved; +} + +Socket::~Socket() { + if (mSocket != -1) { + close(mSocket); + mSocket = -1; + } + mState = State::Destructed; +} + +Socket& Socket::operator=(Socket&& other) noexcept { + if (mSocket != -1) { + close(mSocket); + } + mSocket = other.mSocket; + mState = other.mState; + other.mSocket = -1; + other.mState = State::Moved; + + return *this; +} + +Result Socket::open(int domain, int type, int protocol) { + if (mState != State::New) { + return Result::error("open called on socket in invalid state"); + } + mSocket = ::socket(domain, type | SOCK_CLOEXEC, protocol); + if (mSocket == -1) { + return Result::error(strerror(errno)); + } + mState = State::Open; + return Result::success(); +} + +Result Socket::setInterface(const std::string& interface) { + if (mState != State::Open) { + return Result::error("attempting to set option in invalid state"); + } + int res = ::setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, + interface.c_str(), interface.size()); + + return res == -1 ? Result::error(strerror(errno)) : Result::success(); +} + +Result Socket::setMulticastHopLimit(int hopLimit) { + if (mState != State::Open) { + return Result::error("attempting to set option in invalid state"); + } + int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &hopLimit, sizeof(hopLimit)); + + return res == -1 ? Result::error(strerror(errno)) : Result::success(); +} + +Result Socket::setUnicastHopLimit(int hopLimit) { + if (mState != State::Open) { + return Result::error("attempting to set option in invalid state"); + } + int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + &hopLimit, sizeof(hopLimit)); + + return res == -1 ? Result::error(strerror(errno)) : Result::success(); +} + +Result Socket::setTransparent(bool transparent) { + if (mState != State::Open) { + return Result::error("attempting to set option in invalid state"); + } + int v = transparent ? 1 : 0; + int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_TRANSPARENT, + &v, sizeof(v)); + + return res == -1 ? Result::error(strerror(errno)) : Result::success(); +} + +Result Socket::bind(const Address& address) { + if (mState != State::Open) { + return Result::error("bind called on socket in invalid state"); + } + + int res = ::bind(mSocket, address.get<sockaddr>(), address.size()); + if (res == -1) { + return Result::error(strerror(errno)); + } + + mState = State::Bound; + return Result::success(); +} + +Result Socket::receive(Message* receivingMessage) { + if (receivingMessage == nullptr) { + return Result::error("No receivingMessage provided"); + } + if (mState != State::Bound) { + return Result::error("Attempt to receive on a socket that isn't bound"); + } + + ssize_t rxBytes = ::recv(mSocket, + receivingMessage->data(), + receivingMessage->capacity(), + 0); + if (rxBytes < 0) { + return Result::error(strerror(errno)); + } + + receivingMessage->setSize(static_cast<size_t>(rxBytes)); + return Result::success(); +} + +Result Socket::receiveFrom(Message* receivingMessage, Address* from) { + if (receivingMessage == nullptr) { + return Result::error("No receivingMessage provided"); + } + if (from == nullptr) { + return Result::error("No from address provided"); + } + if (mState != State::Bound) { + return Result::error("Attempt to receive on a socket that isn't bound"); + } + + from->reset(); + sockaddr* source = from->get<sockaddr>(); + socklen_t sourceLen = from->size(); + ssize_t rxBytes = ::recvfrom(mSocket, + receivingMessage->data(), + receivingMessage->capacity(), + 0, + source, + &sourceLen); + if (rxBytes < 0) { + return Result::error(strerror(errno)); + } + + receivingMessage->setSize(static_cast<size_t>(rxBytes)); + return Result::success(); +} + +Result Socket::send(const void* data, size_t size) { + if (mState != State::Bound && mState != State::Open) { + return Result::error("Attempt to send on a socket in invalid state"); + } + + int res = ::send(mSocket, data, size, 0); + if (res == -1) { + return Result::error(strerror(errno)); + } + return Result::success(); +} + +Result Socket::sendTo(const sockaddr& destination, + size_t destinationSize, + const void* data, + size_t size) { + if (mState != State::Bound && mState != State::Open) { + return Result::error("Attempt to send on a socket in invalid state"); + } + + int res = ::sendto(mSocket, data, size, 0, &destination, destinationSize); + if (res == -1) { + return Result::error(strerror(errno)); + } + return Result::success(); +} + +Result Socket::sendTo(const in6_addr& destination, + const void* data, + size_t size) { + sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = destination; + return sendTo(*reinterpret_cast<sockaddr*>(&addr), + sizeof(addr), + data, + size); +} + +Result Socket::sendFrom(const struct in6_addr& fromAddress, + const sockaddr& destination, + size_t destinationSize, + const void* data, + size_t size) { + struct msghdr messageHeader; + memset(&messageHeader, 0, sizeof(messageHeader)); + // Even when sending this struct requires a non-const pointer, even when + // it's only going to be read. Do a const_cast instead of creating a + // method signature with illogical const-behavior. + messageHeader.msg_name = const_cast<struct sockaddr*>(&destination); + messageHeader.msg_namelen = destinationSize; + + struct iovec iov; + messageHeader.msg_iov = &iov; + messageHeader.msg_iovlen = 1; + + memset(&iov, 0, sizeof(iov)); + iov.iov_base = const_cast<void*>(data); + iov.iov_len = size; + + char control[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 }; + messageHeader.msg_control = control; + messageHeader.msg_controllen = sizeof(control); + + struct cmsghdr* controlHeader = CMSG_FIRSTHDR(&messageHeader); + controlHeader->cmsg_level = IPPROTO_IPV6; + controlHeader->cmsg_type = IPV6_PKTINFO; + controlHeader->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + + auto packetInfoData = CMSG_DATA(controlHeader); + auto packetInfo = reinterpret_cast<struct in6_pktinfo*>(packetInfoData); + packetInfo->ipi6_addr = fromAddress; + + int res = ::sendmsg(mSocket, &messageHeader, 0); + if (res == -1) { + int error = errno; + printf("sendmsg failed: %d\n", error); + return Result::error(strerror(error)); + } + return Result::success(); +} + +Result Socket::sendFrom(const in6_addr& fromAddress, + const in6_addr& destination, + const void* data, + size_t size) { + sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = destination; + + return sendFrom(fromAddress, + *reinterpret_cast<sockaddr*>(&addr), + sizeof(addr), + data, + size); +} diff --git a/wifi/ipv6proxy/socket.h b/wifi/ipv6proxy/socket.h new file mode 100644 index 00000000..9cbdda31 --- /dev/null +++ b/wifi/ipv6proxy/socket.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "result.h" + +#include <netinet/in.h> + +#include <stdint.h> +#include <string> + +class Address; +class Message; + +class Socket { +public: + enum class Domain { + IpV4, + IpV6, + Packet, + }; + + enum class Type { + Stream, // A streaming protocol, use this with Infer for TCP + Datagram, // A datagram protocol, use this with Infer for UDP + Raw, // A raw socket + }; + enum class Protocol { + Infer, // Infer the protocol from the type, such as TCP for Stream + Ip, // Internet Protocol for raw sockets + IcmpV6, // ICMPv6 control protocol for Raw sockets + EthIpV6, // Ethernet packets containing IPV6, for packet sockets + }; + + // Construct an empty socket object, next use open() to start using it + Socket(); + // Move construct a socket, The constructed socket will be in the same state + // that |other| is. After this |other| will be in an undefined state and + // should no longer be used. + Socket(Socket&& other) noexcept; + ~Socket(); + + // Move the |other| socket object into this one. If this object has an open + // socket it will be closed first. After that this object will have the + // same state that |other| did. |other| will be left in an undefined state + // and should not be used. + Socket& operator=(Socket&& other) noexcept; + + int get() const { return mSocket; } + + Result open(int domain, int type, int protocol); + + /** Options, these must be called between open and bind **/ + + // Bind to a specific interface regardless of the address that the socket + // is going to bind to. + Result setInterface(const std::string& interface); + + // Set the hop limit for multicast traffic on the socket. Each router hop + // decreases this value by one, when it reaches zero the packet is + // discarded. + Result setMulticastHopLimit(int hopLimit); + + // Set the hop limit for unicast traffic on the socket. Each router hop + // decreases this value by one, when it reaches zero the packet is + // discarded. + Result setUnicastHopLimit(int hopLimit); + + // Configure the socket to be transparent. This allows packets sent to have + // a source address that is different from the network interface's source + // address. + Result setTransparent(bool transparent); + + /** Binding **/ + + Result bind(const Address& address); + + /** Sending and receiving **/ + + Result receive(Message* receivingMessage); + Result receiveFrom(Message* receivingMessage, Address* from); + + Result send(const void* data, size_t size); + + // Send a packet to a specific |destination| of any address type. + Result sendTo(const sockaddr& destination, + size_t destinationSize, + const void* data, + size_t size); + // Convenience function to send to a specific IPv6 address. + Result sendTo(const in6_addr& destination, const void* data, size_t size); + // Convenience method to use sendTo with a more specific sockaddr struct + // without having to specify the size or do the casting. + template<typename T> + Result sendTo(const T& destination, const void* data, size_t size) { + return sendTo(*reinterpret_cast<const sockaddr*>(&destination), + sizeof(destination), + data, + size); + } + + // Send a packet with a specific source IPv6 address to a given + // |destination|. Rewriting the source in this manner usually requires root. + Result sendFrom(const in6_addr& fromAddress, + const sockaddr& destination, + size_t destinationSize, + const void* data, + size_t size); + Result sendFrom(const in6_addr& fromAddress, + const in6_addr& destination, + const void* data, + size_t size); + // Convenience method to use sendFrom with a more specific sockaddr struct + // without having to specify the size or do the casting. + template<typename T> + Result sendFrom(const in6_addr& fromAddress, + const T& destination, + const void* data, + size_t size) { + return sendFrom(fromAddress, + *reinterpret_cast<const sockaddr*>(&destination), + sizeof(destination), + data, + size); + } + +private: + // No copy construction or assignment allowed, support move semantics only + Socket(const Socket&); + Socket& operator=(const Socket&); + + enum class State { + New, + Open, + Bound, + Moved, + Destructed, + }; + + State mState; + int mSocket; +}; + diff --git a/wifi/wpa_supplicant_8_lib/Android.mk b/wifi/wpa_supplicant_8_lib/Android.mk index 76b09691..d6ee9536 100644 --- a/wifi/wpa_supplicant_8_lib/Android.mk +++ b/wifi/wpa_supplicant_8_lib/Android.mk @@ -74,6 +74,7 @@ LOCAL_CFLAGS := $(L_CFLAGS) \ LOCAL_SRC_FILES := $(WPA_SRC_FILE) LOCAL_C_INCLUDES := \ + device/google/gce/include \ $(WPA_SUPPL_DIR_INCLUDE)\ include $(BUILD_STATIC_LIBRARY) diff --git a/x86-vendor.mk b/x86-vendor.mk index 5fa9dc9d..4a2eb10a 100644 --- a/x86-vendor.mk +++ b/x86-vendor.mk @@ -8,7 +8,6 @@ PRODUCT_PROPERTY_OVERRIDES += \ # build quite specifically for the emulator, and might not be # entirely appropriate to inherit from for on-device configurations. PRODUCT_COPY_FILES += \ - device/generic/goldfish/data/etc/config.ini.nexus5:config.ini \ device/generic/goldfish/data/etc/advancedFeatures.ini:advancedFeatures.ini \ device/generic/goldfish/data/etc/encryptionkey.img:encryptionkey.img \ prebuilts/qemu-kernel/x86_64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:kernel-ranchu-64 @@ -17,9 +16,5 @@ PRODUCT_SDK_ADDON_COPY_FILES += \ device/generic/goldfish/data/etc/encryptionkey.img:images/x86/encryptionkey.img \ prebuilts/qemu-kernel/x86_64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:images/x86/kernel-ranchu-64 -PRODUCT_COPY_FILES += \ - device/generic/goldfish/data/etc/x86/emulatorip:$(TARGET_COPY_OUT_VENDOR)/bin/ip - - PRODUCT_SHIPPING_API_LEVEL := 28 TARGET_USES_MKE2FS := true diff --git a/x86_64-vendor.mk b/x86_64-vendor.mk index a41a53e3..16ccf6a2 100644 --- a/x86_64-vendor.mk +++ b/x86_64-vendor.mk @@ -8,7 +8,6 @@ PRODUCT_PROPERTY_OVERRIDES += \ # build quite specifically for the emulator, and might not be # entirely appropriate to inherit from for on-device configurations. PRODUCT_COPY_FILES += \ - device/generic/goldfish/data/etc/config.ini.nexus5:config.ini \ device/generic/goldfish/data/etc/advancedFeatures.ini:advancedFeatures.ini \ device/generic/goldfish/data/etc/encryptionkey.img:encryptionkey.img \ prebuilts/qemu-kernel/x86_64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:kernel-ranchu @@ -17,9 +16,5 @@ PRODUCT_SDK_ADDON_COPY_FILES += \ device/generic/goldfish/data/etc/encryptionkey.img:images/x86_64/encryptionkey.img \ prebuilts/qemu-kernel/x86_64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:images/x86_64/kernel-ranchu -PRODUCT_COPY_FILES += \ - device/generic/goldfish/data/etc/x86/emulatorip:$(TARGET_COPY_OUT_VENDOR)/bin/ip - - PRODUCT_SHIPPING_API_LEVEL := 28 TARGET_USES_MKE2FS := true |