diff --git a/.gitignore b/.gitignore index 85027773b6..5ec57a167f 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,3 @@ GPATH examples/*/sdkconfig examples/*/sdkconfig.old examples/*/build - -# Bootloader files -components/bootloader/src/sdkconfig.old \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0cea70fa7..1e09b55c44 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,8 @@ stages: - build + - unit_test - test + - test_report - deploy before_script: @@ -37,6 +39,12 @@ build_template_app: # branch - git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..." - make defconfig + # Test debug build (default) + - make all V=1 + # Now test release build + - make clean + - sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig + - make defconfig - make all V=1 @@ -62,13 +70,30 @@ build_ssc: expire_in: 6 mos script: - - git clone ssh://git@gitlab.espressif.cn:27227/yinling/SSC.git + - git clone $GITLAB_SSH_SERVER/yinling/SSC.git - cd SSC - git checkout ${CI_BUILD_REF_NAME} || echo "Using SSC default branch..." - make defconfig - chmod +x gen_misc_ng.sh - ./gen_misc_ng.sh +build_esp_idf_tests: + <<: *build_template + artifacts: + paths: + - ./esp-idf-tests/build/*.bin + - ./esp-idf-tests/build/*.elf + - ./esp-idf-tests/build/*.map + - ./esp-idf-tests/build/bootloader/*.bin + expire_in: 6 mos + + script: + - git clone $GITLAB_SSH_SERVER/idf/esp-idf-tests.git + - cd esp-idf-tests + - git checkout ${CI_BUILD_REF_NAME} || echo "Using default branch..." + - make defconfig + - make + build_examples: <<: *build_template artifacts: @@ -86,6 +111,20 @@ build_examples: - cd build_examples - ${IDF_PATH}/make/build_examples.sh +build_docs: + stage: build + image: espressif/esp32-ci-env + tags: + - build_docs + script: + - cd docs + - make html + artifacts: + paths: + - docs/_build/html + expire_in: 1 mos + + test_nvs_on_host: stage: test image: espressif/esp32-ci-env @@ -105,47 +144,32 @@ test_build_system: script: - ./make/test_build_system.sh - - -# template for test jobs -.test_template: &test_template - stage: test - when: on_success +test_report: + stage: test_report only: - master - triggers - + tags: + - test_report variables: - # need user to set SDK_NAME and CONFIG_FILE (may need to set BIN_PATH and APP_NAME later) in before_script - SCRIPT_PATH: /home/gitlab-runner/auto_test_script - BIN_PATH: ${CI_PROJECT_DIR}/SSC/build/ - APP_NAME: ssc - LOG_PATH: $CI_PROJECT_DIR/$CI_BUILD_REF - + LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF" + TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test" + REPORT_PATH: "$CI_PROJECT_DIR/CI_Test_Report" artifacts: when: always paths: - - $LOG_PATH - expire_in: 6 mos - + - $REPORT_PATH + expire_in: 12 mos script: - - cd $SCRIPT_PATH - - python CIRunner.py -l $LOG_PATH -c $SDK_NAME/$CONFIG_FILE bin_path $APP_NAME $BIN_PATH - -sanity_test: - <<: *test_template - tags: - - ESP32 - - SSC_T1_1 - - SSC_T2_1 - - SSC_T1_WAN - before_script: - - SDK_NAME=ESP32_IDF - - CONFIG_FILE=sanity_test.yml + # clone test bench + - git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git + - cd auto_test_script + # generate report + - python CITestReport.py -l $LOG_PATH -t $TEST_CASE_FILE_PATH -p $REPORT_PATH push_master_to_github: - before_script: + before_script: - echo "Not setting up GitLab key, not fetching submodules" stage: deploy only: @@ -165,3 +189,278 @@ push_master_to_github: - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - git remote add github git@github.com:espressif/esp-idf.git - git push --follow-tags github HEAD:master + + +deploy_docs: + before_script: + - echo "Not setting up GitLab key, not fetching submodules" + stage: deploy + only: + - master + - triggers + tags: + - deploy + image: espressif/esp32-ci-env + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config + - export GIT_VER=$(git describe --always) + - cd docs/_build/ + - mv html $GIT_VER + - tar czvf $GIT_VER.tar.gz $GIT_VER + - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH + - ssh $DOCS_SERVER -x "cd $DOCS_PATH && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" + + +# AUTO GENERATED PART START, DO NOT MODIFY CONTENT BELOW +# template for test jobs +.test_template: &test_template + stage: test + when: on_success + only: + - master + - triggers + allow_failure: true + + variables: + # LOCAL_ENV_CONFIG_PATH: define in template and jobs can overwrite if required + LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF + BIN_PATH: "$CI_PROJECT_DIR/SSC/build/" + APP_NAME: "ssc" + LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF" + # append test level folder to TEST_CASE_FILE_PATH in before_script of test job + TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/integration_test" + # jobs MUST set CONFIG_FILE in before_script, and overwrite the variables above if necessary + + artifacts: + when: always + paths: + - $LOG_PATH + expire_in: 6 mos + + script: + # add gitlab ssh key + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + # clone test bench + - git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git + - cd auto_test_script + # run test + - python CIRunner.py -l $LOG_PATH -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH bin_path $APP_NAME $BIN_PATH + + +# template for overnight test jobs +.test_template_night: &test_template_night + <<: *test_template + only: + # can only be triggered + - triggers + script: + # must be night build triggers, otherwise exit without test + - test $NIGHT_BUILD = "Yes" || exit 0 + # add gitlab ssh key + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + # clone test bench + - git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git + - cd auto_test_script + # run test + - python CIRunner.py -l $LOG_PATH -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH bin_path $APP_NAME $BIN_PATH + +# template for unit test jobs +.unit_test_template: &unit_test_template + <<: *test_template + allow_failure: false + stage: unit_test + + variables: + # jobs MUST set CONFIG_FILE in before_script, and overwrite the variables above if necessary + LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF + BIN_PATH: "$CI_PROJECT_DIR/esp-idf-tests/build/" + LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF" + APP_NAME: "ut" + TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/unit_test" + +UT_Function_SYS_01: + <<: *unit_test_template + tags: + - ESP32_IDF + - UT_T1_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/UT_Function_SYS_01.yml + +IT_Function_SYS_01: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_SYS_01.yml + +IT_Function_WIFI_01: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_01.yml + +IT_Function_WIFI_02: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_02.yml + +IT_Function_TCPIP_01: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_01.yml + +IT_Function_TCPIP_02: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_02.yml + +IT_Function_TCPIP_03: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_03.yml + +IT_Function_TCPIP_04: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_04.yml + +IT_Function_TCPIP_05: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_05.yml + +IT_Function_TCPIP_06: + <<: *test_template_night + tags: + - ESP32_IDF + - SSC_T1_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_06.yml + +IT_Function_WIFI_03: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T3_PhyMode + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_03.yml + +IT_Function_WIFI_04: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_APC + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_04.yml + +IT_Function_WIFI_05: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_WEP + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_05.yml + +IT_Function_WIFI_06: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T2_PhyMode + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_06.yml + +IT_Function_TCPIP_07: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T1_2 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_07.yml + +IT_Function_TCPIP_08: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_08.yml + +IT_Function_TCPIP_09: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_09.yml + +IT_Function_TCPIP_10: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T1_2 + - SSC_T2_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_10.yml + +IT_Function_TCPIP_11: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + - SSC_T1_2 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_11.yml + +IT_Function_TCPIP_12: + <<: *test_template + tags: + - ESP32_IDF + - SSC_T1_1 + before_script: + - CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_12.yml diff --git a/.gitmodules b/.gitmodules index df40848261..c26f92e80c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "components/bt/lib"] path = components/bt/lib url = https://github.com/espressif/esp32-bt-lib.git +[submodule "components/micro-ecc/micro-ecc"] + path = components/micro-ecc/micro-ecc + url = https://github.com/kmackay/micro-ecc.git diff --git a/CONTRIBUTING.md b/CONTRIBUTING.rst similarity index 63% rename from CONTRIBUTING.md rename to CONTRIBUTING.rst index b0af761d53..968826790a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.rst @@ -1,12 +1,15 @@ -# Contributions Guide +Contributions Guide +=================== We welcome contributions to the esp-idf project! -## How to Contribute +How to Contribute +----------------- -Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via [Github Pull Requests](https://help.github.com/articles/about-pull-requests/). +Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via `Github Pull Requests `_. -## Before Contributing +Before Contributing +------------------- Before sending us a Pull Request, please consider this list of points: @@ -16,15 +19,16 @@ Before sending us a Pull Request, please consider this list of points: * Is the code adequately commented for people to understand how it is structured? -* Is there documentation or examples that go with code contributions? [There are additional suggestions for writing good examples in the examples README](examples/README.md). +* Is there documentation or examples that go with code contributions? `There are additional suggestions for writing good examples in the examples README `_. * Are comments and documentation written in clear English, with no spelling or grammar errors? -* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" [squashed into previous commits](http://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/)? +* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" `squashed into previous commits `_? * If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback. -## Pull Request Process +Pull Request Process +-------------------- After you open the Pull Request, there will probably be some discussion in the comments field of the request itself. @@ -32,6 +36,10 @@ Once the Pull Request is ready to merge, it will first be merged into our intern If this process passes, it will be merged onto the public github repository. -## Legal Part +Legal Part +---------- + +Before a contribution can be accepted, you will need to sign our :doc:`contributor-agreement`. You will be prompted for this automatically as part of the Pull Request process. + + -Before a contribution can be accepted, you will need to sign our [Contributor Agreement](docs/contributor-agreement.rst). You will be prompted for this automatically as part of the Pull Request process. diff --git a/Kconfig b/Kconfig index 11ea099de2..deb0cea839 100644 --- a/Kconfig +++ b/Kconfig @@ -23,6 +23,26 @@ endmenu source "$COMPONENT_KCONFIGS_PROJBUILD" +choice OPTIMIZATION_LEVEL + prompt "Optimization level" + default OPTIMIZATION_LEVEL_DEBUG + help + This option sets optimization level. + + - for "Release" setting, -Os flag is added to CFLAGS, + and -DNDEBUG flag is added to CPPFLAGS. + + - for "Debug" setting, -Og flag is added to CFLAGS. + + To override any of these settings, set CFLAGS and/or CPPFLAGS + in project makefile, before including $(IDF_PATH)/make/project.mk. + +config OPTIMIZATION_LEVEL_DEBUG + bool "Debug" +config OPTIMIZATION_LEVEL_RELEASE + bool "Release" +endchoice + menu "Component config" source "$COMPONENT_KCONFIGS" endmenu diff --git a/README.md b/README.md index ff645c3392..c01e314f11 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Using Espressif IoT Development Framework with the ESP32 +[![alt text](https://readthedocs.org/projects/docs/badge/?version=latest "Documentation Status")](http://esp-idf.readthedocs.io/en/latest/?badge=latest) + # Setting Up ESP-IDF In the [docs](docs) directory you will find per-platform setup guides: @@ -60,14 +62,15 @@ The simplest way to use the partition table is to `make menuconfig` and choose o In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table. -For more details about partition tables and how to create custom variations, view the `docs/partition_tables.rst` file. +For more details about partition tables and how to create custom variations, view the `docs/partition-tables.rst` file. # Resources -* The [docs directory of the esp-idf repository](docs) contains esp-idf documentation. +* The [docs directory of the esp-idf repository](docs) contains source of [esp-idf](http://esp-idf.readthedocs.io/) documentation. * The [esp32.com forum](http://esp32.com/) is a place to ask questions and find community resources. * [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one. -* If you're interested in contributing to esp-idf, please check the [CONTRIBUTING.md](CONTRIBUTING.md) file. +* If you're interested in contributing to esp-idf, please check the [Contributions Guide](http://esp-idf.readthedocs.io/en/latest/contributing.html>). + diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 394bcc1bd1..50165d0e58 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -20,12 +20,99 @@ config LOG_BOOTLOADER_LEVEL_VERBOSE endchoice config LOG_BOOTLOADER_LEVEL - int - default 0 if LOG_BOOTLOADER_LEVEL_NONE - default 1 if LOG_BOOTLOADER_LEVEL_ERROR - default 2 if LOG_BOOTLOADER_LEVEL_WARN - default 3 if LOG_BOOTLOADER_LEVEL_INFO - default 4 if LOG_BOOTLOADER_LEVEL_DEBUG - default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE + int + default 0 if LOG_BOOTLOADER_LEVEL_NONE + default 1 if LOG_BOOTLOADER_LEVEL_ERROR + default 2 if LOG_BOOTLOADER_LEVEL_WARN + default 3 if LOG_BOOTLOADER_LEVEL_INFO + default 4 if LOG_BOOTLOADER_LEVEL_DEBUG + default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE endmenu + + + +menu "Secure boot configuration" + +choice SECURE_BOOTLOADER + bool "Secure bootloader" + default SECURE_BOOTLOADER_DISABLED + help + Build a bootloader with the secure boot flag enabled. + + Secure bootloader can be one-time-flash (chip will only ever + boot that particular bootloader), or a digest key can be used + to allow the secure bootloader to be re-flashed with + modifications. Secure boot also permanently disables JTAG. + + See docs/security/secure-boot.rst for details. + +config SECURE_BOOTLOADER_DISABLED + bool "Disabled" + +config SECURE_BOOTLOADER_ONE_TIME_FLASH + bool "One-time flash" + help + On first boot, the bootloader will generate a key which is not readable externally or by software. A digest is generated from the bootloader image itself. This digest will be verified on each subsequent boot. + + Enabling this option means that the bootloader cannot be changed after the first time it is booted. + +config SECURE_BOOTLOADER_REFLASHABLE + bool "Reflashable" + help + Generate a reusable secure bootloader key, derived (via SHA-256) from the secure boot signing key. + + This allows the secure bootloader to be re-flashed by anyone with access to the secure boot signing key. + + This option is less secure than one-time flash, because a leak of the digest key from one device allows reflashing of any device that uses it. + +endchoice + +config SECURE_BOOT_SIGNING_KEY + string "Secure boot signing key" + depends on SECURE_BOOTLOADER_ENABLED + default secure_boot_signing_key.pem + help + Path to the key file used to sign partition tables and app images for secure boot. + + Key file is an ECDSA private key (NIST256p curve) in PEM format. + + Path is evaluated relative to the project directory. + + You can generate a new signing key by running the following command: + espsecure.py generate_signing_key secure_boot_signing_key.pem + + See docs/security/secure-boot.rst for details. + +config SECURE_BOOT_DISABLE_JTAG + bool "First boot: Permanently disable JTAG" + depends on SECURE_BOOTLOADER_ENABLED + default Y + help + Bootloader permanently disable JTAG (across entire chip) when enabling secure boot. This happens on first boot of the bootloader. + + It is recommended this option remains set for production environments. + +config SECURE_BOOT_DISABLE_ROM_BASIC + bool "First boot: Permanently disable ROM BASIC fallback" + depends on SECURE_BOOTLOADER_ENABLED + default Y + help + Bootloader permanently disables ROM BASIC (on UART console) as a fallback if the bootloader image becomes invalid. This happens on first boot. + + It is recommended this option remains set in production environments. + +config SECURE_BOOT_TEST_MODE + bool "Test mode: don't actually enable secure boot" + depends on SECURE_BOOTLOADER_ENABLED + default N + help + If this option is set, all permanent secure boot changes (via Efuse) are disabled. + + This option is for testing purposes only - it effectively completely disables secure boot protection. + +config SECURE_BOOTLOADER_ENABLED + bool + default SECURE_BOOTLOADER_ONE_TIME_FLASH || SECURE_BOOTLOADER_REFLASHABLE + +endmenu \ No newline at end of file diff --git a/components/bootloader/Makefile.projbuild b/components/bootloader/Makefile.projbuild index d45cf144e7..3faff53d62 100644 --- a/components/bootloader/Makefile.projbuild +++ b/components/bootloader/Makefile.projbuild @@ -8,44 +8,115 @@ # basically runs Make in the src/ directory but it needs to zero some variables # the ESP-IDF project.mk makefile exports first, to not let them interfere. # -ifeq ("$(IS_BOOTLOADER_BUILD)","") +ifndef IS_BOOTLOADER_BUILD BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH) -BOOTLOADER_BUILD_DIR=$(BUILD_DIR_BASE)/bootloader +BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader) BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin +# signing key path is resolved relative to the project directory +SECURE_BOOT_SIGNING_KEY=$(abspath $(call dequote,$(CONFIG_SECURE_BOOT_SIGNING_KEY))) +export SECURE_BOOT_SIGNING_KEY # used by bootloader_support component + +# Custom recursive make for bootloader sub-project +BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \ + V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) + .PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN) -$(BOOTLOADER_BIN): $(COMPONENT_PATH)/src/sdkconfig - $(Q) PROJECT_PATH= \ - BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) \ - $(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src MAKEFLAGS= V=$(V) TARGET_BIN_LAYOUT="$(BOOTLOADER_TARGET_BIN_LAYOUT)" $(BOOTLOADER_BIN) - -bootloader-clean: - $(Q) PROJECT_PATH= \ - BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) \ - $(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src app-clean MAKEFLAGS= V=$(V) +$(BOOTLOADER_BIN): $(SDKCONFIG_MAKEFILE) + $(BOOTLOADER_MAKE) $@ clean: bootloader-clean -bootloader: $(BOOTLOADER_BIN) - @echo "Bootloader built. Default flash command is:" - @echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)" +ifdef CONFIG_SECURE_BOOTLOADER_DISABLED +# If secure boot disabled, bootloader flashing is integrated +# with 'make flash' and no warnings are printed. -all_binaries: $(BOOTLOADER_BIN) +bootloader: $(BOOTLOADER_BIN) + @echo $(SEPARATOR) + @echo "Bootloader built. Default flash command is:" + @echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^" ESPTOOL_ALL_FLASH_ARGS += 0x1000 $(BOOTLOADER_BIN) -# synchronise the project level config to the component's -# config -$(COMPONENT_PATH)/src/sdkconfig: $(PROJECT_PATH)/sdkconfig - $(Q) cp $< $@ - -# bootloader-flash calls flash in the bootloader dummy project bootloader-flash: $(BOOTLOADER_BIN) - $(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src flash MAKEFLAGS= V=$(V) + $(ESPTOOLPY_WRITE_FLASH) 0x1000 $^ + +else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH + +#### TEMPORARILY DISABLE THIS OPTION +ifneq ("$(IDF_INSECURE_SECURE_BOOT)","1") +bootloader: + @echo "Secure boot features are not yet mature, so the current secure bootloader will not properly secure the device" + @echo "If you flash this bootloader, you will be left with an non-updateable bootloader that is missing features." + @echo "If you really want to do this, set the environment variable IDF_INSECURE_SECURE_BOOT=1 and rerun make." + exit 1 +else + +# One time flashing requires user to run esptool.py command themselves, +# and warning is printed about inability to reflash. + +bootloader: $(BOOTLOADER_BIN) + @echo $(SEPARATOR) + @echo "Bootloader built. One-time flash command is:" + @echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)" + @echo $(SEPARATOR) + @echo "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device" + +endif # IDF_INSECURE_SECURE_BOOT +else ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE +# Reflashable secure bootloader +# generates a digest binary (bootloader + digest) + +#### TEMPORARILY DISABLE THIS OPTION +ifneq ("$(IDF_INSECURE_SECURE_BOOT)","1") +bootloader: + @echo "Secure boot features are not yet mature, so the current secure bootloader will not properly secure the device." + @echo "If using this feature, expect to reflash the bootloader at least one more time." + @echo "If you really want to do this, set the environment variable IDF_INSECURE_SECURE_BOOT=1 and rerun make." + exit 1 +else + +BOOTLOADER_DIGEST_BIN := $(BOOTLOADER_BUILD_DIR)/bootloader-reflash-digest.bin +SECURE_BOOTLOADER_KEY := $(BOOTLOADER_BUILD_DIR)/secure-bootloader-key.bin + +$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY) + $(Q) $(ESPSECUREPY) digest_private_key -k $< $@ + +bootloader: $(BOOTLOADER_DIGEST_BIN) + @echo $(SEPARATOR) + @echo "Bootloader built and secure digest generated. First time flash command is:" + @echo "$(ESPEFUSEPY) burn_key secure_boot $(SECURE_BOOTLOADER_KEY)" + @echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)" + @echo $(SEPARATOR) + @echo "To reflash the bootloader after initial flash:" + @echo "$(ESPTOOLPY_WRITE_FLASH) 0x0 $(BOOTLOADER_DIGEST_BIN)" + @echo $(SEPARATOR) + @echo "* After first boot, only re-flashes of this kind (with same key) will be accepted." + @echo "* Not recommended to re-use the same secure boot keyfile on multiple production devices." + +$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY) + @echo "DIGEST $(notdir $@)" + $(Q) $(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOTLOADER_KEY) -o $@ $< + +endif # IDF_INSECURE_SECURE_BOOT +else +bootloader: + @echo "Invalid bootloader target: bad sdkconfig?" + @exit 1 +endif + +all_binaries: $(BOOTLOADER_BIN) + +bootloader-clean: + $(BOOTLOADER_MAKE) app-clean + rm -f $(SECURE_BOOTLOADER_KEY) $(BOOTLOADER_DIGEST_BIN) + +$(BOOTLOADER_BUILD_DIR): + mkdir -p $@ else -CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include +CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include endif diff --git a/components/bootloader/src/Makefile b/components/bootloader/src/Makefile index f30e314a5f..bb4e64d0b0 100644 --- a/components/bootloader/src/Makefile +++ b/components/bootloader/src/Makefile @@ -4,14 +4,18 @@ # PROJECT_NAME := bootloader -COMPONENTS := esptool_py bootloader log + +#We cannot include the esp32 component directly but we need its includes. +#This is fixed by adding CFLAGS from Makefile.projbuild +COMPONENTS := esptool_py bootloader bootloader_support log spi_flash micro-ecc # The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included. # # IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op IS_BOOTLOADER_BUILD := 1 +export IS_BOOTLOADER_BUILD -#We cannot include the esp32 component directly but we need its includes. -#This is fixed by adding CFLAGS from Makefile.projbuild +# include the top-level "project" include directory, for sdkconfig.h +CFLAGS += -I$(BUILD_DIR_BASE)/../include include $(IDF_PATH)/make/project.mk diff --git a/components/bootloader/src/main/bootloader_config.h b/components/bootloader/src/main/bootloader_config.h index 709ff41b16..4559d5f816 100644 --- a/components/bootloader/src/main/bootloader_config.h +++ b/components/bootloader/src/main/bootloader_config.h @@ -20,12 +20,11 @@ extern "C" { #endif + +#include "esp_flash_data_types.h" + #define BOOT_VERSION "V0.1" #define SPI_SEC_SIZE 0x1000 -#define MEM_CACHE(offset) (uint8_t *)(0x3f400000 + (offset)) -#define CACHE_READ_32(offset) ((uint32_t *)(0x3f400000 + (offset))) -#define PARTITION_ADD 0x4000 -#define PARTITION_MAGIC 0x50AA #define IROM_LOW 0x400D0000 #define IROM_HIGH 0x40400000 #define DROM_LOW 0x3F400000 @@ -35,74 +34,6 @@ extern "C" #define RTC_DATA_LOW 0x50000000 #define RTC_DATA_HIGH 0x50002000 -/*spi mode,saved in third byte in flash */ -enum { - SPI_MODE_QIO, - SPI_MODE_QOUT, - SPI_MODE_DIO, - SPI_MODE_DOUT, - SPI_MODE_FAST_READ, - SPI_MODE_SLOW_READ -}; -/* spi speed*/ -enum { - SPI_SPEED_40M, - SPI_SPEED_26M, - SPI_SPEED_20M, - SPI_SPEED_80M = 0xF -}; -/*suppport flash size in esp32 */ -enum { - SPI_SIZE_1MB = 0, - SPI_SIZE_2MB, - SPI_SIZE_4MB, - SPI_SIZE_8MB, - SPI_SIZE_16MB, - SPI_SIZE_MAX -}; - - -struct flash_hdr { - char magic; - char blocks; - char spi_mode; /* flag of flash read mode in unpackage and usage in future */ - char spi_speed: 4; /* low bit */ - char spi_size: 4; - unsigned int entry_addr; - uint8_t encrypt_flag; /* encrypt flag */ - uint8_t secury_boot_flag; /* secury boot flag */ - char extra_header[14]; /* ESP32 additional header, unused by second bootloader */ -}; - -/* each header of flash bin block */ -struct block_hdr { - unsigned int load_addr; - unsigned int data_len; -}; - -/* OTA selection structure (two copies in the OTA data partition.) - - Size of 32 bytes is friendly to flash encryption */ -typedef struct { - uint32_t ota_seq; - uint8_t seq_label[24]; - uint32_t crc; /* CRC32 of ota_seq field only */ -} ota_select; - -typedef struct { - uint32_t offset; - uint32_t size; -} partition_pos_t; - -typedef struct { - uint16_t magic; - uint8_t type; /* partition Type */ - uint8_t subtype; /* part_subtype */ - partition_pos_t pos; - uint8_t label[16]; /* label for the partition */ - uint8_t reserved[4]; /* reserved */ -} partition_info_t; - #define PART_TYPE_APP 0x00 #define PART_SUBTYPE_FACTORY 0x00 #define PART_SUBTYPE_OTA_FLAG 0x10 @@ -120,20 +51,15 @@ typedef struct { #define SPI_ERROR_LOG "spi flash error" typedef struct { - partition_pos_t ota_info; - partition_pos_t factory; - partition_pos_t test; - partition_pos_t ota[16]; + esp_partition_pos_t ota_info; + esp_partition_pos_t factory; + esp_partition_pos_t test; + esp_partition_pos_t ota[16]; uint32_t app_count; uint32_t selected_subtype; } bootloader_state_t; -void boot_cache_redirect( uint32_t pos, size_t size ); -uint32_t get_bin_len(uint32_t pos); - bool flash_encrypt(bootloader_state_t *bs); -bool secure_boot(void); - #ifdef __cplusplus } diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index a61ea77d59..6b92aaf346 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -3,7 +3,7 @@ // 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 @@ -33,6 +33,9 @@ #include "soc/timer_group_reg.h" #include "sdkconfig.h" +#include "esp_image_format.h" +#include "esp_secure_boot.h" +#include "bootloader_flash.h" #include "bootloader_config.h" @@ -49,15 +52,16 @@ flash cache is down and the app CPU is in reset. We do have a stack, so we can d extern void Cache_Flush(int); void bootloader_main(); -void unpack_load_app(const partition_pos_t *app_node); -void print_flash_info(struct flash_hdr* pfhdr); -void IRAM_ATTR set_cache_and_start_app(uint32_t drom_addr, +static void unpack_load_app(const esp_partition_pos_t *app_node); +void print_flash_info(const esp_image_header_t* pfhdr); +void set_cache_and_start_app(uint32_t drom_addr, uint32_t drom_load_addr, uint32_t drom_size, uint32_t irom_addr, uint32_t irom_load_addr, uint32_t irom_size, uint32_t entry_addr); +static void update_flash_config(const esp_image_header_t* pfhdr); void IRAM_ATTR call_start_cpu0() @@ -93,53 +97,6 @@ void IRAM_ATTR call_start_cpu0() bootloader_main(); } -/** - * @function : get_bin_len - * @description: get bin's length - * - * @inputs: pos bin locate address in flash - * @return: uint32 length of bin,if bin MAGIC error return 0 - */ - -uint32_t get_bin_len(uint32_t pos) -{ - uint32_t len = 8 + 16; - uint8_t i; - ESP_LOGD(TAG, "pos %d %x",pos,*(uint8_t *)pos); - if(0xE9 != *(uint8_t *)pos) { - return 0; - } - for (i = 0; i < *(uint8_t *)(pos + 1); i++) { - len += *(uint32_t *)(pos + len + 4) + 8; - } - if (len % 16 != 0) { - len = (len / 16 + 1) * 16; - } else { - len += 16; - } - ESP_LOGD(TAG, "bin length = %d", len); - return len; -} - -/** - * @function : boot_cache_redirect - * @description: Configure several pages in flash map so that `size` bytes - * starting at `pos` are mapped to 0x3f400000. - * This sets up mapping only for PRO CPU. - * - * @inputs: pos address in flash - * size size of the area to map, in bytes - */ -void boot_cache_redirect( uint32_t pos, size_t size ) -{ - uint32_t pos_aligned = pos & 0xffff0000; - uint32_t count = (size + 0xffff) / 0x10000; - Cache_Read_Disable( 0 ); - Cache_Flush( 0 ); - ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", pos_aligned, count ); - cache_flash_mmu_set( 0, 0, 0x3f400000, pos_aligned, 64, count ); - Cache_Read_Enable( 0 ); -} /** * @function : load_partition_table @@ -147,95 +104,113 @@ void boot_cache_redirect( uint32_t pos, size_t size ) * OTA info sector, factory app sector, and test app sector. * * @inputs: bs bootloader state structure used to save the data - * addr address of partition table in flash * @return: return true, if the partition table is loaded (and MD5 checksum is valid) * */ -bool load_partition_table(bootloader_state_t* bs, uint32_t addr) +bool load_partition_table(bootloader_state_t* bs) { - partition_info_t partition; - uint32_t end = addr + 0x1000; - int index = 0; + const esp_partition_info_t *partitions; + const int ESP_PARTITION_TABLE_DATA_LEN = 0xC00; /* length of actual data (signature is appended to this) */ + const int MAX_PARTITIONS = ESP_PARTITION_TABLE_DATA_LEN / sizeof(esp_partition_info_t); char *partition_usage; ESP_LOGI(TAG, "Partition Table:"); ESP_LOGI(TAG, "## Label Usage Type ST Offset Length"); - while (addr < end) { - ESP_LOGD(TAG, "load partition table entry from %x(%08x)", addr, MEM_CACHE(addr)); - memcpy(&partition, MEM_CACHE(addr), sizeof(partition)); - ESP_LOGD(TAG, "type=%x subtype=%x", partition.type, partition.subtype); +#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED + if(esp_secure_boot_enabled()) { + ESP_LOGI(TAG, "Verifying partition table signature..."); + esp_err_t err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to verify partition table signature."); + return false; + } + ESP_LOGD(TAG, "Partition table signature verified"); + } +#endif + + partitions = bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN); + if (!partitions) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN); + return false; + } + ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions); + + for(int i = 0; i < MAX_PARTITIONS; i++) { + const esp_partition_info_t *partition = &partitions[i]; + ESP_LOGD(TAG, "load partition table entry 0x%x", (intptr_t)partition); + ESP_LOGD(TAG, "type=%x subtype=%x", partition->type, partition->subtype); partition_usage = "unknown"; - if (partition.magic == PARTITION_MAGIC) { /* valid partition definition */ - switch(partition.type) { - case PART_TYPE_APP: /* app partition */ - switch(partition.subtype) { - case PART_SUBTYPE_FACTORY: /* factory binary */ - bs->factory = partition.pos; - partition_usage = "factory app"; - break; - case PART_SUBTYPE_TEST: /* test binary */ - bs->test = partition.pos; - partition_usage = "test app"; - break; - default: - /* OTA binary */ - if ((partition.subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) { - bs->ota[partition.subtype & PART_SUBTYPE_OTA_MASK] = partition.pos; - ++bs->app_count; - partition_usage = "OTA app"; - } - else { - partition_usage = "Unknown app"; - } - break; + if (partition->magic != ESP_PARTITION_MAGIC) { + /* invalid partition definition indicates end-of-table */ + break; + } + + /* valid partition table */ + switch(partition->type) { + case PART_TYPE_APP: /* app partition */ + switch(partition->subtype) { + case PART_SUBTYPE_FACTORY: /* factory binary */ + bs->factory = partition->pos; + partition_usage = "factory app"; + break; + case PART_SUBTYPE_TEST: /* test binary */ + bs->test = partition->pos; + partition_usage = "test app"; + break; + default: + /* OTA binary */ + if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) { + bs->ota[partition->subtype & PART_SUBTYPE_OTA_MASK] = partition->pos; + ++bs->app_count; + partition_usage = "OTA app"; } - break; /* PART_TYPE_APP */ - case PART_TYPE_DATA: /* data partition */ - switch(partition.subtype) { - case PART_SUBTYPE_DATA_OTA: /* ota data */ - bs->ota_info = partition.pos; - partition_usage = "OTA data"; - break; - case PART_SUBTYPE_DATA_RF: - partition_usage = "RF data"; - break; - case PART_SUBTYPE_DATA_WIFI: - partition_usage = "WiFi data"; - break; - default: - partition_usage = "Unknown data"; - break; + else { + partition_usage = "Unknown app"; } - break; /* PARTITION_USAGE_DATA */ - default: /* other partition type */ break; } - } - /* invalid partition magic number */ - else { - break; /* todo: validate md5 */ + break; /* PART_TYPE_APP */ + case PART_TYPE_DATA: /* data partition */ + switch(partition->subtype) { + case PART_SUBTYPE_DATA_OTA: /* ota data */ + bs->ota_info = partition->pos; + partition_usage = "OTA data"; + break; + case PART_SUBTYPE_DATA_RF: + partition_usage = "RF data"; + break; + case PART_SUBTYPE_DATA_WIFI: + partition_usage = "WiFi data"; + break; + default: + partition_usage = "Unknown data"; + break; + } + break; /* PARTITION_USAGE_DATA */ + default: /* other partition type */ + break; } /* print partition type info */ - ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", index, partition.label, partition_usage, - partition.type, partition.subtype, - partition.pos.offset, partition.pos.size); - index++; - addr += sizeof(partition); + ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", i, partition->label, partition_usage, + partition->type, partition->subtype, + partition->pos.offset, partition->pos.size); } + bootloader_munmap(partitions); + ESP_LOGI(TAG,"End of partition table"); return true; } -static uint32_t ota_select_crc(const ota_select *s) +static uint32_t ota_select_crc(const esp_ota_select_entry_t *s) { return crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4); } -static bool ota_select_valid(const ota_select *s) +static bool ota_select_valid(const esp_ota_select_entry_t *s) { return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s); } @@ -251,36 +226,51 @@ void bootloader_main() { ESP_LOGI(TAG, "Espressif ESP32 2nd stage bootloader v. %s", BOOT_VERSION); - struct flash_hdr fhdr; + esp_image_header_t fhdr; bootloader_state_t bs; - SpiFlashOpResult spiRet1,spiRet2; - ota_select sa,sb; + SpiFlashOpResult spiRet1,spiRet2; + esp_ota_select_entry_t sa,sb; + const esp_ota_select_entry_t *ota_select_map; + memset(&bs, 0, sizeof(bs)); ESP_LOGI(TAG, "compile time " __TIME__ ); - /* close watch dog here */ + /* disable watch dog here */ REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN ); REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); SPIUnlock(); - /*register first sector in drom0 page 0 */ - boot_cache_redirect( 0, 0x5000 ); - memcpy((unsigned int *) &fhdr, MEM_CACHE(0x1000), sizeof(struct flash_hdr) ); + if(esp_image_load_header(0x1000, &fhdr) != ESP_OK) { + ESP_LOGE(TAG, "failed to load bootloader header!"); + return; + } print_flash_info(&fhdr); - if (!load_partition_table(&bs, PARTITION_ADD)) { + update_flash_config(&fhdr); + + if (!load_partition_table(&bs)) { ESP_LOGE(TAG, "load partition table error!"); return; } - partition_pos_t load_part_pos; + esp_partition_pos_t load_part_pos; if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition //ESP_LOGE("OTA info sector handling is not implemented"); - boot_cache_redirect(bs.ota_info.offset, bs.ota_info.size ); - memcpy(&sa,MEM_CACHE(bs.ota_info.offset & 0x0000ffff),sizeof(sa)); - memcpy(&sb,MEM_CACHE((bs.ota_info.offset + 0x1000)&0x0000ffff) ,sizeof(sb)); + if (bs.ota_info.size < 2 * sizeof(esp_ota_select_entry_t)) { + ESP_LOGE(TAG, "ERROR: ota_info partition size %d is too small (minimum %d bytes)", bs.ota_info.size, sizeof(esp_ota_select_entry_t)); + return; + } + ota_select_map = bootloader_mmap(bs.ota_info.offset, bs.ota_info.size); + if (!ota_select_map) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs.ota_info.offset, bs.ota_info.size); + return; + } + sa = ota_select_map[0]; + sb = ota_select_map[1]; + bootloader_munmap(ota_select_map); + if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) { // init status flash load_part_pos = bs.ota[0]; @@ -290,14 +280,14 @@ void bootloader_main() sb.crc = ota_select_crc(&sb); Cache_Read_Disable(0); - spiRet1 = SPIEraseSector(bs.ota_info.offset/0x1000); - spiRet2 = SPIEraseSector(bs.ota_info.offset/0x1000+1); + spiRet1 = SPIEraseSector(bs.ota_info.offset/0x1000); + spiRet2 = SPIEraseSector(bs.ota_info.offset/0x1000+1); if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) { ESP_LOGE(TAG, SPI_ERROR_LOG); return; } - spiRet1 = SPIWrite(bs.ota_info.offset,(uint32_t *)&sa,sizeof(ota_select)); - spiRet2 = SPIWrite(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(ota_select)); + spiRet1 = SPIWrite(bs.ota_info.offset,(uint32_t *)&sa,sizeof(esp_ota_select_entry_t)); + spiRet2 = SPIWrite(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(esp_ota_select_entry_t)); if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) { ESP_LOGE(TAG, SPI_ERROR_LOG); return; @@ -326,35 +316,61 @@ void bootloader_main() } ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos); - if(fhdr.secury_boot_flag == 0x01) { - /* protect the 2nd_boot */ - if(false == secure_boot()){ - ESP_LOGE(TAG, "secure boot failed"); - return; - } + +#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED + /* Generate secure digest from this bootloader to protect future + modifications */ + esp_err_t err = esp_secure_boot_permanently_enable(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.", err); + /* Allow booting to continue, as the failure is probably + due to user-configured EFUSEs for testing... + */ } +#endif if(fhdr.encrypt_flag == 0x01) { - /* encrypt flash */ + /* encrypt flash */ if (false == flash_encrypt(&bs)) { ESP_LOGE(TAG, "flash encrypt failed"); return; } } - // copy sections to RAM, set up caches, and start application + // copy loaded segments to RAM, set up caches for mapped segments, and start application unpack_load_app(&load_part_pos); } -void unpack_load_app(const partition_pos_t* partition) +static void unpack_load_app(const esp_partition_pos_t* partition) { - boot_cache_redirect(partition->offset, partition->size); + esp_err_t err; + esp_image_header_t image_header; + uint32_t image_length; - uint32_t pos = 0; - struct flash_hdr image_header; - memcpy(&image_header, MEM_CACHE(pos), sizeof(image_header)); - pos += sizeof(image_header); + /* TODO: verify the app image as part of OTA boot decision, so can have fallbacks */ + err = esp_image_basic_verify(partition->offset, &image_length); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err); + return; + } + +#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED + if (esp_secure_boot_enabled()) { + ESP_LOGI(TAG, "Verifying app signature @ 0x%x (length 0x%x)", partition->offset, image_length); + err = esp_secure_boot_verify_signature(partition->offset, image_length); + if (err != ESP_OK) { + ESP_LOGE(TAG, "App image @ 0x%x failed signature verification (%d)", partition->offset, err); + return; + } + ESP_LOGD(TAG, "App signature is valid"); + } +#endif + + if (esp_image_load_header(partition->offset, &image_header) != ESP_OK) { + ESP_LOGE(TAG, "Failed to load app image header @ 0x%x", partition->offset); + return; + } uint32_t drom_addr = 0; uint32_t drom_load_addr = 0; @@ -363,24 +379,27 @@ void unpack_load_app(const partition_pos_t* partition) uint32_t irom_load_addr = 0; uint32_t irom_size = 0; - /* Reload the RTC memory sections whenever a non-deepsleep reset - is occuring */ + /* Reload the RTC memory segments whenever a non-deepsleep reset + is occurring */ bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET; ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic, - image_header.blocks, + image_header.segment_count, image_header.spi_mode, image_header.spi_size, (unsigned)image_header.entry_addr); - for (uint32_t section_index = 0; - section_index < image_header.blocks; - ++section_index) { - struct block_hdr section_header = {0}; - memcpy(§ion_header, MEM_CACHE(pos), sizeof(section_header)); - pos += sizeof(section_header); + for (int segment = 0; segment < image_header.segment_count; segment++) { + esp_image_segment_header_t segment_header; + uint32_t data_offs; + if(esp_image_load_segment_header(segment, partition->offset, + &image_header, &segment_header, + &data_offs) != ESP_OK) { + ESP_LOGE(TAG, "failed to load segment header #%d", segment); + return; + } - const uint32_t address = section_header.load_addr; + const uint32_t address = segment_header.load_addr; bool load = true; bool map = false; if (address == 0x00000000) { // padding, ignore block @@ -392,47 +411,50 @@ void unpack_load_app(const partition_pos_t* partition) } if (address >= DROM_LOW && address < DROM_HIGH) { - ESP_LOGD(TAG, "found drom section, map from %08x to %08x", pos, - section_header.load_addr); - drom_addr = partition->offset + pos - sizeof(section_header); - drom_load_addr = section_header.load_addr; - drom_size = section_header.data_len + sizeof(section_header); + ESP_LOGD(TAG, "found drom segment, map from %08x to %08x", data_offs, + segment_header.load_addr); + drom_addr = data_offs; + drom_load_addr = segment_header.load_addr; + drom_size = segment_header.data_len + sizeof(segment_header); load = false; map = true; } if (address >= IROM_LOW && address < IROM_HIGH) { - ESP_LOGD(TAG, "found irom section, map from %08x to %08x", pos, - section_header.load_addr); - irom_addr = partition->offset + pos - sizeof(section_header); - irom_load_addr = section_header.load_addr; - irom_size = section_header.data_len + sizeof(section_header); + ESP_LOGD(TAG, "found irom segment, map from %08x to %08x", data_offs, + segment_header.load_addr); + irom_addr = data_offs; + irom_load_addr = segment_header.load_addr; + irom_size = segment_header.data_len + sizeof(segment_header); load = false; map = true; } if (!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) { - ESP_LOGD(TAG, "Skipping RTC code section at %08x\n", pos); + ESP_LOGD(TAG, "Skipping RTC code segment at %08x\n", data_offs); load = false; } if (!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) { - ESP_LOGD(TAG, "Skipping RTC data section at %08x\n", pos); + ESP_LOGD(TAG, "Skipping RTC data segment at %08x\n", data_offs); load = false; } - ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos, - section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":""); + ESP_LOGI(TAG, "segment %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", segment, data_offs - sizeof(esp_image_segment_header_t), + segment_header.load_addr, segment_header.data_len, segment_header.data_len, (load)?"load":(map)?"map":""); - if (!load) { - pos += section_header.data_len; - continue; + if (load) { + const void *data = bootloader_mmap(data_offs, segment_header.data_len); + if(!data) { + ESP_LOGE(TAG, "bootloader_mmap(0x%xc, 0x%x) failed", + data_offs, segment_header.data_len); + return; + } + memcpy((void *)segment_header.load_addr, data, segment_header.data_len); + bootloader_munmap(data); } - - memcpy((void*) section_header.load_addr, MEM_CACHE(pos), section_header.data_len); - pos += section_header.data_len; } - + set_cache_and_start_app(drom_addr, drom_load_addr, drom_size, @@ -442,7 +464,7 @@ void unpack_load_app(const partition_pos_t* partition) image_header.entry_addr); } -void IRAM_ATTR set_cache_and_start_app( +void set_cache_and_start_app( uint32_t drom_addr, uint32_t drom_load_addr, uint32_t drom_size, @@ -453,9 +475,7 @@ void IRAM_ATTR set_cache_and_start_app( { ESP_LOGD(TAG, "configure drom and irom and start"); Cache_Read_Disable( 0 ); - Cache_Read_Disable( 1 ); Cache_Flush( 0 ); - Cache_Flush( 1 ); uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count ); int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count ); @@ -471,7 +491,8 @@ void IRAM_ATTR set_cache_and_start_app( REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 ); REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 ); Cache_Read_Enable( 0 ); - Cache_Read_Enable( 1 ); + + // Application will need to do Cache_Flush(1) and Cache_Read_Enable(1) ESP_LOGD(TAG, "start: 0x%08x", entry_addr); typedef void (*entry_t)(void); @@ -482,67 +503,84 @@ void IRAM_ATTR set_cache_and_start_app( (*entry)(); } +static void update_flash_config(const esp_image_header_t* pfhdr) +{ + uint32_t size; + switch(pfhdr->spi_size) { + case ESP_IMAGE_FLASH_SIZE_1MB: + size = 1; + break; + case ESP_IMAGE_FLASH_SIZE_2MB: + size = 2; + break; + case ESP_IMAGE_FLASH_SIZE_4MB: + size = 4; + break; + case ESP_IMAGE_FLASH_SIZE_8MB: + size = 8; + break; + case ESP_IMAGE_FLASH_SIZE_16MB: + size = 16; + break; + default: + size = 2; + } + Cache_Read_Disable( 0 ); + // Set flash chip size + SPIParamCfg(g_rom_flashchip.deviceId, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff); + // TODO: set mode + // TODO: set frequency + Cache_Flush(0); + Cache_Read_Enable( 0 ); +} -void print_flash_info(struct flash_hdr* pfhdr) +void print_flash_info(const esp_image_header_t* phdr) { #if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE) - struct flash_hdr fhdr = *pfhdr; - - ESP_LOGD(TAG, "magic %02x", fhdr.magic ); - ESP_LOGD(TAG, "blocks %02x", fhdr.blocks ); - ESP_LOGD(TAG, "spi_mode %02x", fhdr.spi_mode ); - ESP_LOGD(TAG, "spi_speed %02x", fhdr.spi_speed ); - ESP_LOGD(TAG, "spi_size %02x", fhdr.spi_size ); + ESP_LOGD(TAG, "magic %02x", phdr->magic ); + ESP_LOGD(TAG, "segments %02x", phdr->segment_count ); + ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode ); + ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed ); + ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size ); const char* str; - switch ( fhdr.spi_speed ) { - case SPI_SPEED_40M: + switch ( phdr->spi_speed ) { + case ESP_IMAGE_SPI_SPEED_40M: str = "40MHz"; break; - - case SPI_SPEED_26M: + case ESP_IMAGE_SPI_SPEED_26M: str = "26.7MHz"; break; - - case SPI_SPEED_20M: + case ESP_IMAGE_SPI_SPEED_20M: str = "20MHz"; break; - - case SPI_SPEED_80M: + case ESP_IMAGE_SPI_SPEED_80M: str = "80MHz"; break; - default: str = "20MHz"; break; } ESP_LOGI(TAG, "SPI Speed : %s", str ); - - - switch ( fhdr.spi_mode ) { - case SPI_MODE_QIO: + switch ( phdr->spi_mode ) { + case ESP_IMAGE_SPI_MODE_QIO: str = "QIO"; break; - - case SPI_MODE_QOUT: + case ESP_IMAGE_SPI_MODE_QOUT: str = "QOUT"; break; - - case SPI_MODE_DIO: + case ESP_IMAGE_SPI_MODE_DIO: str = "DIO"; break; - - case SPI_MODE_DOUT: + case ESP_IMAGE_SPI_MODE_DOUT: str = "DOUT"; break; - - case SPI_MODE_FAST_READ: + case ESP_IMAGE_SPI_MODE_FAST_READ: str = "FAST READ"; break; - - case SPI_MODE_SLOW_READ: + case ESP_IMAGE_SPI_MODE_SLOW_READ: str = "SLOW READ"; break; default: @@ -551,31 +589,24 @@ void print_flash_info(struct flash_hdr* pfhdr) } ESP_LOGI(TAG, "SPI Mode : %s", str ); - - - switch ( fhdr.spi_size ) { - case SPI_SIZE_1MB: + switch ( phdr->spi_size ) { + case ESP_IMAGE_FLASH_SIZE_1MB: str = "1MB"; break; - - case SPI_SIZE_2MB: + case ESP_IMAGE_FLASH_SIZE_2MB: str = "2MB"; break; - - case SPI_SIZE_4MB: + case ESP_IMAGE_FLASH_SIZE_4MB: str = "4MB"; break; - - case SPI_SIZE_8MB: + case ESP_IMAGE_FLASH_SIZE_8MB: str = "8MB"; break; - - case SPI_SIZE_16MB: + case ESP_IMAGE_FLASH_SIZE_16MB: str = "16MB"; break; - default: - str = "1MB"; + str = "2MB"; break; } ESP_LOGI(TAG, "SPI Flash Size : %s", str ); diff --git a/components/bootloader/src/main/component.mk b/components/bootloader/src/main/component.mk index 8c8ea4cb63..01b07b9498 100644 --- a/components/bootloader/src/main/component.mk +++ b/components/bootloader/src/main/component.mk @@ -1,12 +1,9 @@ # -# Main Makefile. This is basically the same as a component makefile. +# Main bootloader Makefile. # -# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default, -# this will take the sources in the src/ directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the esp-idf build system document if you need to do this. +# This is basically the same as a component makefile, but in the case of the bootloader +# we pull in bootloader-specific linker arguments. # -COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld +COMPONENT_ADD_LDFLAGS := -L $(COMPONENT_PATH) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld -include $(IDF_PATH)/make/component_common.mk diff --git a/components/bootloader/src/main/esp32.bootloader.ld b/components/bootloader/src/main/esp32.bootloader.ld index af97bda3ad..6a77eb6ade 100644 --- a/components/bootloader/src/main/esp32.bootloader.ld +++ b/components/bootloader/src/main/esp32.bootloader.ld @@ -15,7 +15,7 @@ MEMORY of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but are connected to the data port of the CPU and eg allow bytewise access. */ dport0_seg (RW) : org = 0x3FF00000, len = 0x10 /* IO */ - iram_seg (RWX) : org = 0x40098000, len = 0x1000 + iram_seg (RWX) : org = 0x40080000, len = 0x400 /* 1k of IRAM used by bootloader functions which need to flush/enable APP CPU cache */ iram_pool_1_seg (RWX) : org = 0x40078000, len = 0x8000 /* IRAM POOL1, used for APP CPU cache. We can abuse it in bootloader because APP CPU is still held in reset, until we enable APP CPU cache */ dram_seg (RW) : org = 0x3FFC0000, len = 0x20000 /* Shared RAM, minus rom bss/data/stack.*/ } diff --git a/components/bootloader/src/main/flash_encrypt.c b/components/bootloader/src/main/flash_encrypt.c index 26e66aa039..2b1479097d 100644 --- a/components/bootloader/src/main/flash_encrypt.c +++ b/components/bootloader/src/main/flash_encrypt.c @@ -17,6 +17,7 @@ #include "esp_types.h" #include "esp_attr.h" #include "esp_log.h" +#include "esp_err.h" #include "rom/cache.h" #include "rom/ets_sys.h" @@ -30,6 +31,7 @@ #include "sdkconfig.h" #include "bootloader_config.h" +#include "esp_image_format.h" static const char* TAG = "flash_encrypt"; @@ -90,103 +92,97 @@ bool flash_encrypt_write(uint32_t pos, uint32_t len) Cache_Read_Enable(0); return true; } + + /** * @function : flash_encrypt * @description: encrypt 2nd boot ,partition table ,factory bin ��test bin (if use)��ota bin * ��OTA info sector. * * @inputs: bs bootloader state structure used to save the data - * + * * @return: return true, if the encrypt flash success - * + * */ bool flash_encrypt(bootloader_state_t *bs) { - uint32_t bin_len = 0; - uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT); - uint8_t count = bitcount(flash_crypt_cnt); - int i = 0; - ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count); + esp_err_t err; + uint32_t image_len = 0; + uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT); + uint8_t count = bitcount(flash_crypt_cnt); + ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count); - if ((count % 2) == 0) { - boot_cache_redirect( 0, 64*1024); - /* encrypt iv and abstruct */ - if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) { - ESP_LOGE(TAG, "encrypt iv and abstract error"); - return false; - } + if ((count % 2) == 0) { + /* encrypt iv and abstract */ + if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) { + ESP_LOGE(TAG, "encrypt iv and abstract error"); + return false; + } + + /* encrypt bootloader image */ + err = esp_image_basic_verify(0x1000, &image_len); + if(err == ESP_OK && image_len != 0) { + if (false == flash_encrypt_write(0x1000, image_len)) { + ESP_LOGE(TAG, "encrypt 2nd boot error"); + return false; + } + } else { + ESP_LOGE(TAG, "2nd boot len error"); + return false; + } - /* encrypt write boot bin*/ - bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000)); - if(bin_len != 0) { - if (false == flash_encrypt_write(0x1000, bin_len)) { - ESP_LOGE(TAG, "encrypt 2nd boot error"); - return false; - } - } else { - ESP_LOGE(TAG, "2nd boot len error"); - return false; - } /* encrypt partition table */ - if (false == flash_encrypt_write(PARTITION_ADD, SPI_SEC_SIZE)) { - ESP_LOGE(TAG, "encrypt partition table error"); - return false; - } + if (false == flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) { + ESP_LOGE(TAG, "encrypt partition table error"); + return false; + } /* encrypt write factory bin */ - if(bs->factory.offset != 0x00) { - ESP_LOGD(TAG, "have factory bin"); - boot_cache_redirect(bs->factory.offset, bs->factory.size); - bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->factory.offset&0xffff)); - if(bin_len != 0) { - if (false == flash_encrypt_write(bs->factory.offset, bin_len)) { - ESP_LOGE(TAG, "encrypt factory bin error"); - return false; - } - } - } + if(bs->factory.offset != 0 && bs->factory.size != 0) { + ESP_LOGD(TAG, "have factory bin"); + if (false == flash_encrypt_write(bs->factory.offset, bs->factory.size)) { + ESP_LOGE(TAG, "encrypt factory bin error"); + return false; + } + } + /* encrypt write test bin */ - if(bs->test.offset != 0x00) { - ESP_LOGD(TAG, "have test bin"); - boot_cache_redirect(bs->test.offset, bs->test.size); - bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->test.offset&0xffff)); - if(bin_len != 0) { - if (false == flash_encrypt_write(bs->test.offset, bin_len)) { - ESP_LOGE(TAG, "encrypt test bin error"); - return false; - } - } - } + if(bs->test.offset != 0 && bs->test.size != 0) { + ESP_LOGD(TAG, "have test bin"); + if (false == flash_encrypt_write(bs->test.offset, bs->test.size)) { + ESP_LOGE(TAG, "encrypt test bin error"); + return false; + } + } + /* encrypt write ota bin */ - for (i = 0;i<16;i++) { - if(bs->ota[i].offset != 0x00) { - ESP_LOGD(TAG, "have ota[%d] bin",i); - boot_cache_redirect(bs->ota[i].offset, bs->ota[i].size); - bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->ota[i].offset&0xffff)); - if(bin_len != 0) { - if (false == flash_encrypt_write(bs->ota[i].offset, bin_len)) { - ESP_LOGE(TAG, "encrypt ota bin error"); - return false; - } - } - } - } + for (int i = 0; i < 16; i++) { + if(bs->ota[i].offset != 0 && bs->ota[i].size != 0) { + ESP_LOGD(TAG, "have ota[%d] bin",i); + if (false == flash_encrypt_write(bs->ota[i].offset, bs->ota[i].size)) { + ESP_LOGE(TAG, "encrypt ota bin error"); + return false; + } + } + } + /* encrypt write ota info bin */ - if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) { - ESP_LOGE(TAG, "encrypt ota info error"); - return false; - } - REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04); - REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */ - REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */ - while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */ - ESP_LOGW(TAG, "burn flash_crypt_cnt"); - REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */ - REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */ - while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */ - return true; - } else { - ESP_LOGI(TAG, "flash already encrypted."); - return true; - } + if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) { + ESP_LOGE(TAG, "encrypt ota info error"); + return false; + } + + REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04); + REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */ + REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */ + while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */ + ESP_LOGW(TAG, "burn flash_crypt_cnt"); + REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */ + REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */ + while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */ + return true; + } else { + ESP_LOGI(TAG, "flash already encrypted."); + return true; + } } diff --git a/components/bootloader/src/main/secure_boot.c b/components/bootloader/src/main/secure_boot.c deleted file mode 100644 index 3dfdbd1412..0000000000 --- a/components/bootloader/src/main/secure_boot.c +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// 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 - -#include "esp_attr.h" -#include "esp_types.h" -#include "esp_log.h" - -#include "rom/cache.h" -#include "rom/ets_sys.h" -#include "rom/spi_flash.h" -#include "rom/secure_boot.h" - -#include "soc/dport_reg.h" -#include "soc/io_mux_reg.h" -#include "soc/efuse_reg.h" -#include "soc/rtc_cntl_reg.h" - -#include "sdkconfig.h" - -#include "bootloader_config.h" - -static const char* TAG = "secure_boot"; - -/** - * @function : secure_boot_generate - * @description: generate boot abstract & iv - * - * @inputs: bool - */ -bool secure_boot_generate(uint32_t bin_len){ - SpiFlashOpResult spiRet; - uint16_t i; - uint32_t buf[32]; - if (bin_len % 128 != 0) { - bin_len = (bin_len / 128 + 1) * 128; - } - ets_secure_boot_start(); - ets_secure_boot_rd_iv(buf); - ets_secure_boot_hash(NULL); - Cache_Read_Disable(0); - /* iv stored in sec 0 */ - spiRet = SPIEraseSector(0); - if (spiRet != SPI_FLASH_RESULT_OK) - { - ESP_LOGE(TAG, SPI_ERROR_LOG); - return false; - } - /* write iv to flash, 0x0000, 128 bytes (1024 bits) */ - spiRet = SPIWrite(0, buf, 128); - if (spiRet != SPI_FLASH_RESULT_OK) - { - ESP_LOGE(TAG, SPI_ERROR_LOG); - return false; - } - ESP_LOGD(TAG, "write iv to flash."); - Cache_Read_Enable(0); - /* read 4K code image from flash, for test */ - for (i = 0; i < bin_len; i+=128) { - ets_secure_boot_hash((uint32_t *)(0x3f400000 + 0x1000 + i)); - } - - ets_secure_boot_obtain(); - ets_secure_boot_rd_abstract(buf); - ets_secure_boot_finish(); - Cache_Read_Disable(0); - /* write abstract to flash, 0x0080, 64 bytes (512 bits) */ - spiRet = SPIWrite(0x80, buf, 64); - if (spiRet != SPI_FLASH_RESULT_OK) { - ESP_LOGE(TAG, SPI_ERROR_LOG); - return false; - } - ESP_LOGD(TAG, "write abstract to flash."); - Cache_Read_Enable(0); - return true; -} - - -/** - * @function : secure_boot - * @description: protect boot code in flash - * - * @inputs: bool - */ -bool secure_boot(void){ - uint32_t bin_len = 0; - if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0) - { - ESP_LOGD(TAG, "already secure boot !"); - return true; - } else { - boot_cache_redirect( 0, 64*1024); - bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000)); - if (bin_len == 0) { - ESP_LOGE(TAG, "boot len is error"); - return false; - } - if (false == secure_boot_generate(bin_len)){ - ESP_LOGE(TAG, "secure boot generate failed"); - return false; - } - } - - REG_SET_BIT(EFUSE_BLK0_WDATA6_REG, EFUSE_RD_ABS_DONE_0); - REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */ - REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */ - while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */ - ESP_LOGW(TAG, "burn abstract_done_0"); - REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */ - REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */ - while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */ - ESP_LOGI(TAG, "read EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG)); - return true; - -} diff --git a/components/bootloader_support/README.rst b/components/bootloader_support/README.rst new file mode 100644 index 0000000000..54ac861c9b --- /dev/null +++ b/components/bootloader_support/README.rst @@ -0,0 +1,9 @@ +Bootloader Support Component +============================ + +Overview +-------- + +"Bootloader support" contains APIs which are used by the bootloader but are also needed for the main app. + +Code in this component needs to be aware of being executed in a bootloader environment (no RTOS available, BOOTLOADER_BUILD macro set) or in an esp-idf app environment (RTOS running, need locking support.) diff --git a/components/bootloader_support/component.mk b/components/bootloader_support/component.mk new file mode 100755 index 0000000000..a7e5b849dc --- /dev/null +++ b/components/bootloader_support/component.mk @@ -0,0 +1,35 @@ +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := include_priv + +ifdef IS_BOOTLOADER_BUILD +# share "private" headers with the bootloader component +# eventual goal: all functionality that needs this lives in bootloader_support +COMPONENT_ADD_INCLUDEDIRS += include_priv +endif + +COMPONENT_SRCDIRS := src + +# +# Secure boot signing key support +# +ifdef CONFIG_SECURE_BOOTLOADER_ENABLED + +# this path is created relative to the component build directory +SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin) + +$(SECURE_BOOT_SIGNING_KEY): + @echo "Need to generate secure boot signing key." + @echo "One way is to run this command:" + @echo "$(ESPSECUREPY) generate_signing_key $@" + @echo "Keep key file safe after generating." + @echo "(See secure boot documentation for risks & alternatives.)" + @exit 1 + +$(SECURE_BOOT_VERIFICATION_KEY): $(SECURE_BOOT_SIGNING_KEY) + $(ESPSECUREPY) extract_public_key --keyfile $< $@ + +COMPONENT_EXTRA_CLEAN += $(SECURE_BOOT_VERIFICATION_KEY) + +COMPONENT_EMBED_FILES := $(SECURE_BOOT_VERIFICATION_KEY) + +endif diff --git a/components/bootloader_support/include/esp_image_format.h b/components/bootloader_support/include/esp_image_format.h new file mode 100644 index 0000000000..a32a50a4a5 --- /dev/null +++ b/components/bootloader_support/include/esp_image_format.h @@ -0,0 +1,132 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP32_IMAGE_FORMAT_H +#define __ESP32_IMAGE_FORMAT_H + +#include +#include + +#define ESP_ERR_IMAGE_BASE 0x2000 +#define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1) +#define ESP_ERR_IMAGE_INVALID (ESP_ERR_IMAGE_BASE + 2) + +/* Support for app/bootloader image parsing + Can be compiled as part of app or bootloader code. +*/ + +/* SPI flash mode, used in esp_image_header_t */ +typedef enum { + ESP_IMAGE_SPI_MODE_QIO, + ESP_IMAGE_SPI_MODE_QOUT, + ESP_IMAGE_SPI_MODE_DIO, + ESP_IMAGE_SPI_MODE_DOUT, + ESP_IMAGE_SPI_MODE_FAST_READ, + ESP_IMAGE_SPI_MODE_SLOW_READ +} esp_image_spi_mode_t; + +/* SPI flash clock frequency */ +enum { + ESP_IMAGE_SPI_SPEED_40M, + ESP_IMAGE_SPI_SPEED_26M, + ESP_IMAGE_SPI_SPEED_20M, + ESP_IMAGE_SPI_SPEED_80M = 0xF +} esp_image_spi_freq_t; + +/* Supported SPI flash sizes */ +typedef enum { + ESP_IMAGE_FLASH_SIZE_1MB = 0, + ESP_IMAGE_FLASH_SIZE_2MB, + ESP_IMAGE_FLASH_SIZE_4MB, + ESP_IMAGE_FLASH_SIZE_8MB, + ESP_IMAGE_FLASH_SIZE_16MB, + ESP_IMAGE_FLASH_SIZE_MAX +} esp_image_flash_size_t; + +#define ESP_IMAGE_HEADER_MAGIC 0xE9 + +/* Main header of binary image */ +typedef struct { + uint8_t magic; + uint8_t segment_count; + uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */ + uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */ + uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */ + uint32_t entry_addr; + uint8_t encrypt_flag; /* encrypt flag */ + uint8_t extra_header[15]; /* ESP32 additional header, unused by second bootloader */ +} esp_image_header_t; + +/* Header of binary image segment */ +typedef struct { + uint32_t load_addr; + uint32_t data_len; +} esp_image_segment_header_t; + + +/** + * @brief Read an ESP image header from flash. + * + * @param src_addr Address in flash to load image header. Must be 4 byte aligned. + * @param[out] image_header Pointer to an esp_image_header_t struture to be filled with data. If the function fails, contents are undefined. + * + * @return ESP_OK if image header was loaded, ESP_ERR_IMAGE_FLASH_FAIL + * if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header + * appears invalid. + */ +esp_err_t esp_image_load_header(uint32_t src_addr, esp_image_header_t *image_header); + +/** + * @brief Read the segment header and data offset of a segment in the image. + * + * @param index Index of the segment to load information for. + * @param src_addr Base address in flash of the image. + * @param[in] image_header Pointer to the flash image header, already loaded by @ref esp_image_load_header(). + * @param[out] segment_header Pointer to a segment header structure to be filled with data. If the function fails, contents are undefined. + * @param[out] segment_data_offset Pointer to the data offset of the segment. + * + * @return ESP_OK if segment_header & segment_data_offset were loaded successfully, ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header appears invalid, ESP_ERR_INVALID_ARG if the index is invalid. + */ +esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset); + + +/** + * @brief Return length of an image in flash. Non-cryptographically validates image integrity in the process. + * + * If the image has a secure boot signature appended, the signature is not checked and this length is not included in the result. + * + * Image validation checks: + * - Magic byte + * - No single segment longer than 16MB + * - Total image no longer than 16MB + * - 8 bit image checksum is valid + * + * @param src_addr Offset of the start of the image in flash. Must be 4 byte aligned. + * @param[out] length Length of the image, set to a value if the image is valid. Can be null. + * + * @return ESP_OK if image is valid, ESP_FAIL or ESP_ERR_IMAGE_INVALID on errors. + * + */ +esp_err_t esp_image_basic_verify(uint32_t src_addr, uint32_t *length); + + +typedef struct { + uint32_t drom_addr; + uint32_t drom_load_addr; + uint32_t drom_size; + uint32_t irom_addr; + uint32_t irom_load_addr; + uint32_t irom_size; +} esp_image_flash_mapping_t; + +#endif diff --git a/components/bootloader_support/include/esp_secure_boot.h b/components/bootloader_support/include/esp_secure_boot.h new file mode 100644 index 0000000000..f9fc57708d --- /dev/null +++ b/components/bootloader_support/include/esp_secure_boot.h @@ -0,0 +1,75 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP32_SECUREBOOT_H +#define __ESP32_SECUREBOOT_H + +#include +#include +#include "soc/efuse_reg.h" + +/* Support functions for secure boot features. + + Can be compiled as part of app or bootloader code. +*/ + +/** @brief Is secure boot currently enabled in hardware? + * + * Secure boot is enabled if the ABS_DONE_0 efuse is blown. This means + * that the ROM bootloader code will only boot a verified secure + * bootloader digest from now on. + * + * @return true if secure boot is enabled. + */ +static inline bool esp_secure_boot_enabled(void) { + return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0; +} + + +/** @brief Enable secure boot if it is not already enabled. + * + * @important If this function succeeds, secure boot is permanently + * enabled on the chip via efuse. + * + * @important This function is intended to be called from bootloader code only. + * + * If secure boot is not yet enabled for bootloader, this will + * generate the secure boot digest and enable secure boot by blowing + * the EFUSE_RD_ABS_DONE_0 efuse. + * + * This function does not verify secure boot of the bootloader (the + * ROM bootloader does this.) + * + * Will fail if efuses have been part-burned in a way that indicates + * secure boot should not or could not be correctly enabled. + * + * + * @return ESP_ERR_INVALID_STATE if efuse state doesn't allow + * secure boot to be enabled cleanly. ESP_OK if secure boot + * is enabled on this chip from now on. + */ +esp_err_t esp_secure_boot_permanently_enable(void); + +/** @brief Verify the secure boot signature (determinstic ECDSA w/ SHA256) appended to some binary data in flash. + * + * Public key is compiled into the calling program. See docs/security/secure-boot.rst for details. + * + * @param src_addr Starting offset of the data in flash. + * @param length Length of data in bytes. Signature is appended -after- length bytes. + * + * @return ESP_OK if signature is valid, ESP_ERR_INVALID_STATE if + * signature fails, ESP_FAIL for other failures (ie can't read flash). + */ +esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length); + +#endif diff --git a/components/bootloader_support/include_priv/bootloader_flash.h b/components/bootloader_support/include_priv/bootloader_flash.h new file mode 100644 index 0000000000..769c47b904 --- /dev/null +++ b/components/bootloader_support/include_priv/bootloader_flash.h @@ -0,0 +1,69 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __BOOTLOADER_FLASH_H +#define __BOOTLOADER_FLASH_H + +#include +#include +#include +#include + +/* Provide a Flash API for bootloader_support code, + that can be used from bootloader or app code. + + This header is available to source code in the bootloader & + bootloader_support components only. +*/ + +/** + * @brief Map a region of flash to data memory + * + * @important In bootloader code, only one region can be bootloader_mmaped at once. The previous region must be bootloader_munmapped before another region is mapped. + * + * @important In app code, these functions are not thread safe. + * + * Call bootloader_munmap once for each successful call to bootloader_mmap. + * + * In esp-idf app, this function maps directly to spi_flash_mmap. + * + * @param offset - Starting flash offset to map to memory. + * @param length - Length of data to map. + * + * @return Pointer to mapped data memory (at src_addr), or NULL + * if an allocation error occured. + */ +const void *bootloader_mmap(uint32_t src_addr, uint32_t size); + + +/** + * @brief Unmap a previously mapped region of flash + * + * Call bootloader_munmap once for each successful call to bootloader_mmap. + */ +void bootloader_munmap(const void *mapping); + +/** + * @brief Read data from Flash. + * + * @note Both src and dest have to be 4-byte aligned. + * + * @param src source address of the data in Flash. + * @param dest pointer to the destination buffer + * @param size length of data + * + * @return esp_err_t + */ +esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size); + +#endif diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c new file mode 100644 index 0000000000..3fd107dea8 --- /dev/null +++ b/components/bootloader_support/src/bootloader_flash.c @@ -0,0 +1,122 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 + +#include +#include +#include /* including in bootloader for error values */ + +#ifndef BOOTLOADER_BUILD +/* Normal app version maps to esp_spi_flash.h operations... + */ +static const char *TAG = "bootloader_mmap"; + +static spi_flash_mmap_memory_t map; + +const void *bootloader_mmap(uint32_t src_addr, uint32_t size) +{ + if (map) { + ESP_LOGE(TAG, "tried to bootloader_mmap twice"); + return NULL; /* existing mapping in use... */ + } + const void *result = NULL; + esp_err_t err = spi_flash_mmap(src_addr, size, SPI_FLASH_MMAP_DATA, &result, &map); + if (err != ESP_OK) { + result = NULL; + } + return result; +} + +void bootloader_munmap(const void *mapping) +{ + if(mapping && map) { + spi_flash_munmap(map); + } + map = 0; +} + +esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size) +{ + return spi_flash_read(src, dest, size); +} + +#else +/* Bootloader version, uses ROM functions only */ +#include +#include + +static const char *TAG = "bootloader_flash"; + +static bool mapped; + +const void *bootloader_mmap(uint32_t src_addr, uint32_t size) +{ + if (mapped) { + ESP_LOGE(TAG, "tried to bootloader_mmap twice"); + return NULL; /* can't map twice */ + } + + uint32_t src_addr_aligned = src_addr & 0xffff0000; + uint32_t count = (size + (src_addr - src_addr_aligned) + 0xffff) / 0x10000; + Cache_Read_Disable(0); + Cache_Flush(0); + ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", src_addr_aligned, count ); + cache_flash_mmu_set( 0, 0, 0x3f400000, src_addr_aligned, 64, count ); + Cache_Read_Enable( 0 ); + + mapped = true; + + return (void *)(0x3f400000 + (src_addr - src_addr_aligned)); +} + +void bootloader_munmap(const void *mapping) +{ + if (mapped) { + /* Full MMU reset */ + Cache_Read_Disable(0); + Cache_Flush(0); + mmu_init(0); + mapped = false; + } +} + +esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size) +{ + if(src_addr & 3) { + ESP_LOGE(TAG, "bootloader_flash_read src_addr 0x%x not 4-byte aligned", src_addr); + return ESP_FAIL; + } + if((intptr_t)dest & 3) { + ESP_LOGE(TAG, "bootloader_flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest); + return ESP_FAIL; + } + + Cache_Read_Disable(0); + Cache_Flush(0); + SpiFlashOpResult r = SPIRead(src_addr, dest, size); + Cache_Read_Enable(0); + + switch(r) { + case SPI_FLASH_RESULT_OK: + return ESP_OK; + case SPI_FLASH_RESULT_ERR: + return ESP_ERR_FLASH_OP_FAIL; + case SPI_FLASH_RESULT_TIMEOUT: + return ESP_ERR_FLASH_OP_TIMEOUT; + default: + return ESP_FAIL; + } +} + +#endif diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c new file mode 100644 index 0000000000..42a3e4ffe2 --- /dev/null +++ b/components/bootloader_support/src/esp_image_format.c @@ -0,0 +1,161 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 + +#include +#include +#include + +const static char *TAG = "esp_image"; + +#define SIXTEEN_MB 0x1000000 +#define ESP_ROM_CHECKSUM_INITIAL 0xEF + +esp_err_t esp_image_load_header(uint32_t src_addr, esp_image_header_t *image_header) +{ + esp_err_t err; + ESP_LOGD(TAG, "reading image header @ 0x%x", src_addr); + + err = bootloader_flash_read(src_addr, image_header, sizeof(esp_image_header_t)); + + if (err == ESP_OK) { + if (image_header->magic != ESP_IMAGE_HEADER_MAGIC) { + ESP_LOGE(TAG, "image at 0x%x has invalid magic byte", src_addr); + err = ESP_ERR_IMAGE_INVALID; + } + if (image_header->spi_mode > ESP_IMAGE_SPI_MODE_SLOW_READ) { + ESP_LOGW(TAG, "image at 0x%x has invalid SPI mode %d", src_addr, image_header->spi_mode); + } + if (image_header->spi_speed > ESP_IMAGE_SPI_SPEED_80M) { + ESP_LOGW(TAG, "image at 0x%x has invalid SPI speed %d", src_addr, image_header->spi_speed); + } + if (image_header->spi_size > ESP_IMAGE_FLASH_SIZE_MAX) { + ESP_LOGW(TAG, "image at 0x%x has invalid SPI size %d", src_addr, image_header->spi_size); + } + } + + if (err != ESP_OK) { + bzero(image_header, sizeof(esp_image_header_t)); + } + return err; +} + +esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset) +{ + esp_err_t err = ESP_OK; + uint32_t next_addr = src_addr + sizeof(esp_image_header_t); + + if(index >= image_header->segment_count) { + ESP_LOGE(TAG, "index %d higher than segment count %d", index, image_header->segment_count); + return ESP_ERR_INVALID_ARG; + } + + for(int i = 0; i <= index && err == ESP_OK; i++) { + ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr); + err = bootloader_flash_read(next_addr, segment_header, sizeof(esp_image_segment_header_t)); + if (err == ESP_OK) { + if ((segment_header->data_len & 3) != 0 + || segment_header->data_len >= SIXTEEN_MB) { + ESP_LOGE(TAG, "invalid segment length 0x%x", segment_header->data_len); + err = ESP_ERR_IMAGE_INVALID; + } + next_addr += sizeof(esp_image_segment_header_t); + ESP_LOGV(TAG, "segment data length 0x%x data starts 0x%x", segment_header->data_len, next_addr); + *segment_data_offset = next_addr; + next_addr += segment_header->data_len; + } + } + + if (err != ESP_OK) { + *segment_data_offset = 0; + bzero(segment_header, sizeof(esp_image_segment_header_t)); + } + + return err; +} + +esp_err_t esp_image_basic_verify(uint32_t src_addr, uint32_t *p_length) +{ + esp_err_t err; + uint8_t buf[16]; + uint8_t checksum = ESP_ROM_CHECKSUM_INITIAL; + esp_image_header_t image_header; + esp_image_segment_header_t segment_header = { 0 }; + uint32_t segment_data_offs = 0; + const uint8_t *segment_data; + uint32_t end_addr; + uint32_t length; + + if (p_length != NULL) { + *p_length = 0; + } + + err = esp_image_load_header(src_addr, &image_header); + if (err != ESP_OK) { + return err; + } + + ESP_LOGD(TAG, "reading %d image segments", image_header.segment_count); + + /* Checksum each segment's data */ + for (int i = 0; i < image_header.segment_count; i++) { + err = esp_image_load_segment_header(i, src_addr, &image_header, + &segment_header, &segment_data_offs); + if (err != ESP_OK) { + return err; + } + + segment_data = bootloader_mmap(segment_data_offs, segment_header.data_len); + if (segment_data == NULL) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", segment_data_offs, segment_header.data_len); + return ESP_FAIL; + } + for(int i = 0; i < segment_header.data_len; i++) { + checksum ^= segment_data[i]; + } + bootloader_munmap(segment_data); + } + + /* End of image, verify checksum */ + end_addr = segment_data_offs + segment_header.data_len; + + if (end_addr < src_addr) { + ESP_LOGE(TAG, "image offset has wrapped"); + return ESP_ERR_IMAGE_INVALID; + } + + length = end_addr - src_addr; + if (length >= SIXTEEN_MB) { + ESP_LOGE(TAG, "invalid total length 0x%x", length); + return ESP_ERR_IMAGE_INVALID; + } + + /* image padded to next full 16 byte block, with checksum byte at very end */ + ESP_LOGV(TAG, "unpadded image length 0x%x", length); + length += 16; /* always pad by at least 1 byte */ + length = length - (length % 16); + ESP_LOGV(TAG, "padded image length 0x%x", length); + ESP_LOGD(TAG, "reading checksum block at 0x%x", src_addr + length - 16); + bootloader_flash_read(src_addr + length - 16, buf, 16); + if (checksum != buf[15]) { + ESP_LOGE(TAG, "checksum failed. Calculated 0x%x read 0x%x", + checksum, buf[15]); + return ESP_ERR_IMAGE_INVALID; + } + + if (p_length != NULL) { + *p_length = length; + } + return ESP_OK; +} diff --git a/components/bootloader_support/src/secure_boot.c b/components/bootloader_support/src/secure_boot.c new file mode 100644 index 0000000000..d908d39c38 --- /dev/null +++ b/components/bootloader_support/src/secure_boot.c @@ -0,0 +1,222 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 + +#include "esp_attr.h" +#include "esp_types.h" +#include "esp_log.h" + +#include "rom/cache.h" +#include "rom/ets_sys.h" +#include "rom/spi_flash.h" +#include "rom/secure_boot.h" + +#include "soc/dport_reg.h" +#include "soc/io_mux_reg.h" +#include "soc/efuse_reg.h" +#include "soc/rtc_cntl_reg.h" + +#include "sdkconfig.h" + +#include "bootloader_flash.h" +#include "esp_image_format.h" +#include "esp_secure_boot.h" + +static const char* TAG = "secure_boot"; + +#define HASH_BLOCK_SIZE 128 +#define IV_LEN HASH_BLOCK_SIZE +#define DIGEST_LEN 64 + +/** + * @function : secure_boot_generate + * @description: generate boot digest (aka "abstract") & iv + * + * @inputs: image_len - length of image to calculate digest for + */ +static bool secure_boot_generate(uint32_t image_len){ + SpiFlashOpResult spiRet; + /* buffer is uint32_t not uint8_t to meet ROM SPI API signature */ + uint32_t buf[IV_LEN / sizeof(uint32_t)]; + const void *image; + + /* hardware secure boot engine only takes full blocks, so round up the + image length. The additional data should all be 0xFF. + */ + if (image_len % HASH_BLOCK_SIZE != 0) { + image_len = (image_len / HASH_BLOCK_SIZE + 1) * HASH_BLOCK_SIZE; + } + ets_secure_boot_start(); + ets_secure_boot_rd_iv(buf); + ets_secure_boot_hash(NULL); + Cache_Read_Disable(0); + /* iv stored in sec 0 */ + spiRet = SPIEraseSector(0); + if (spiRet != SPI_FLASH_RESULT_OK) + { + ESP_LOGE(TAG, "SPI erase failed %d", spiRet); + return false; + } + Cache_Read_Enable(0); + + /* write iv to flash, 0x0000, 128 bytes (1024 bits) */ + ESP_LOGD(TAG, "write iv to flash."); + spiRet = SPIWrite(0, buf, IV_LEN); + if (spiRet != SPI_FLASH_RESULT_OK) + { + ESP_LOGE(TAG, "SPI write failed %d", spiRet); + return false; + } + bzero(buf, sizeof(buf)); + + /* generate digest from image contents */ + image = bootloader_mmap(0x1000, image_len); + if (!image) { + ESP_LOGE(TAG, "bootloader_mmap(0x1000, 0x%x) failed", image_len); + return false; + } + for (int i = 0; i < image_len; i+= HASH_BLOCK_SIZE) { + ets_secure_boot_hash(image + i/sizeof(void *)); + } + bootloader_munmap(image); + + ets_secure_boot_obtain(); + ets_secure_boot_rd_abstract(buf); + ets_secure_boot_finish(); + + ESP_LOGD(TAG, "write digest to flash."); + spiRet = SPIWrite(0x80, buf, DIGEST_LEN); + if (spiRet != SPI_FLASH_RESULT_OK) { + ESP_LOGE(TAG, "SPI write failed %d", spiRet); + return false; + } + ESP_LOGD(TAG, "write digest to flash."); + Cache_Read_Enable(0); + return true; +} + +/* Burn values written to the efuse write registers */ +static inline void burn_efuses() +{ +#ifdef CONFIG_SECURE_BOOT_TEST_MODE + ESP_LOGE(TAG, "SECURE BOOT TEST MODE. Not really burning any efuses!"); +#else + REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */ + REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */ + while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */ + REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */ + REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */ + while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */ +#endif +} + +esp_err_t esp_secure_boot_permanently_enable(void) { + esp_err_t err; + uint32_t image_len = 0; + if (esp_secure_boot_enabled()) + { + ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing.."); + return ESP_OK; + } + + err = esp_image_basic_verify(0x1000, &image_len); + if (err != ESP_OK) { + ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err); + return err; + } + + uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG); + bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2; + bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2; + if (efuse_key_read_protected == false + && efuse_key_write_protected == false + && REG_READ(EFUSE_BLK2_RDATA0_REG) == 0 + && REG_READ(EFUSE_BLK2_RDATA1_REG) == 0 + && REG_READ(EFUSE_BLK2_RDATA2_REG) == 0 + && REG_READ(EFUSE_BLK2_RDATA3_REG) == 0 + && REG_READ(EFUSE_BLK2_RDATA4_REG) == 0 + && REG_READ(EFUSE_BLK2_RDATA5_REG) == 0 + && REG_READ(EFUSE_BLK2_RDATA6_REG) == 0 + && REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) { + ESP_LOGI(TAG, "Generating new secure boot key..."); + /* reuse the secure boot IV generation function to generate + the key, as this generator uses the hardware RNG. */ + uint32_t buf[32]; + ets_secure_boot_start(); + ets_secure_boot_rd_iv(buf); + ets_secure_boot_finish(); + for (int i = 0; i < 8; i++) { + ESP_LOGV(TAG, "EFUSE_BLK2_WDATA%d_REG = 0x%08x", i, buf[i]); + REG_WRITE(EFUSE_BLK2_WDATA0_REG + 4*i, buf[i]); + } + bzero(buf, sizeof(buf)); + burn_efuses(); + ESP_LOGI(TAG, "Read & write protecting new key..."); + REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2); + burn_efuses(); + efuse_key_read_protected = true; + efuse_key_write_protected = true; + + } else { + ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2"); + } + + ESP_LOGI(TAG, "Generating secure boot digest..."); + if (false == secure_boot_generate(image_len)){ + ESP_LOGE(TAG, "secure boot generation failed"); + return ESP_FAIL; + } + ESP_LOGI(TAG, "Digest generation complete."); + + if (!efuse_key_read_protected) { + ESP_LOGE(TAG, "Pre-loaded key is not read protected. Refusing to blow secure boot efuse."); + return ESP_ERR_INVALID_STATE; + } + if (!efuse_key_write_protected) { + ESP_LOGE(TAG, "Pre-loaded key is not write protected. Refusing to blow secure boot efuse."); + return ESP_ERR_INVALID_STATE; + } + + ESP_LOGI(TAG, "blowing secure boot efuse..."); + ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG)); + + uint32_t new_wdata6 = EFUSE_RD_ABS_DONE_0; + + #ifdef CONFIG_SECURE_BOOT_DISABLE_JTAG + ESP_LOGI(TAG, "disabling JTAG..."); + new_wdata6 |= EFUSE_RD_DISABLE_JTAG; + #endif + + #ifdef CONFIG_SECURE_BOOT_DISABLE_UART_BOOTLOADER + ESP_LOGI(TAG, "disabling UART bootloader..."); + new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE_S; + #endif + + REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6); + burn_efuses(); + uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG); + ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA6 %x", after); + if (after & EFUSE_RD_ABS_DONE_0) { + ESP_LOGI(TAG, "secure boot is now enabled for bootloader image"); + return ESP_OK; + } else { +#ifdef CONFIG_SECURE_BOOT_TEST_MODE + ESP_LOGE(TAG, "secure boot not enabled due to test mode"); +#else + ESP_LOGE(TAG, "secure boot not enabled for bootloader image, EFUSE_RD_ABS_DONE_0 is probably write protected!"); +#endif + return ESP_ERR_INVALID_STATE; + } +} diff --git a/components/bootloader_support/src/secure_boot_signatures.c b/components/bootloader_support/src/secure_boot_signatures.c new file mode 100644 index 0000000000..6d47651b2f --- /dev/null +++ b/components/bootloader_support/src/secure_boot_signatures.c @@ -0,0 +1,107 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "sdkconfig.h" + +#include "bootloader_flash.h" +#include "esp_log.h" +#include "esp_image_format.h" +#include "esp_secure_boot.h" + +#include "uECC.h" + +#ifdef BOOTLOADER_BUILD +#include "rom/sha.h" +typedef SHA_CTX sha_context; +#else +#include "hwcrypto/sha.h" +typedef esp_sha_context sha_context; +#endif + +typedef struct { + uint32_t version; + uint8_t signature[64]; +} signature_block_t; + +static const char* TAG = "secure_boot"; + +extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start"); +extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end"); + +#define SIGNATURE_VERIFICATION_KEYLEN 64 + +esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) +{ + sha_context sha; + uint8_t digest[32]; + ptrdiff_t keylen; + const uint8_t *data, *digest_data; + uint32_t digest_len; + const signature_block_t *sigblock; + bool is_valid; + + ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length); + + data = bootloader_mmap(src_addr, length + sizeof(signature_block_t)); + if(data == NULL) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(signature_block_t)); + return ESP_FAIL; + } + + sigblock = (const signature_block_t *)(data + length); + + if (sigblock->version != 0) { + ESP_LOGE(TAG, "src 0x%x has invalid signature version field 0x%08x", src_addr, sigblock->version); + goto unmap_and_fail; + } + +#ifdef BOOTLOADER_BUILD + /* Use ROM SHA functions directly */ + ets_sha_enable(); + ets_sha_init(&sha); + digest_len = length * 8; + digest_data = data; + while (digest_len > 0) { + uint32_t chunk_len = (digest_len > 64) ? 64 : digest_len; + ets_sha_update(&sha, SHA2_256, digest_data, chunk_len); + digest_len -= chunk_len; + digest_data += chunk_len / 8; + } + ets_sha_finish(&sha, SHA2_256, digest); + ets_sha_disable(); +#else + /* Use thread-safe esp-idf SHA layer */ + esp_sha256_init(&sha); + esp_sha256_start(&sha, false); + esp_sha256_update(&sha, data, length); + esp_sha256_finish(&sha, digest); + esp_sha256_free(&sha); +#endif + + keylen = signature_verification_key_end - signature_verification_key_start; + if(keylen != SIGNATURE_VERIFICATION_KEYLEN) { + ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen); + goto unmap_and_fail; + } + + is_valid = uECC_verify(signature_verification_key_start, + digest, sizeof(digest), sigblock->signature, + uECC_secp256r1()); + + bootloader_munmap(data); + return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID; + + unmap_and_fail: + bootloader_munmap(data); + return ESP_FAIL; +} diff --git a/components/bt/component.mk b/components/bt/component.mk index e88651aa13..91620ddc14 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -2,20 +2,16 @@ # Component Makefile # -#COMPONENT_ADD_INCLUDEDIRS := - COMPONENT_ADD_INCLUDEDIRS := include CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses LIBS := btdm_app -COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \ +COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \ $(addprefix -l,$(LIBS)) \ $(LINKER_SCRIPTS) -include $(IDF_PATH)/make/component_common.mk - ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) $(COMPONENT_LIBRARY): $(ALL_LIB_FILES) diff --git a/components/bt/include/bt.h b/components/bt/include/bt.h index 1e89f96aa1..f476334b12 100644 --- a/components/bt/include/bt.h +++ b/components/bt/include/bt.h @@ -28,37 +28,36 @@ extern "C" { * * This function should be called only once, before any other BT functions are called. */ -void bt_controller_init(); +void bt_controller_init(void); -/** @brief: vhci_host_callback +/** @brief vhci_host_callback * used for vhci call host function to notify what host need to do * * notify_host_send_available: notify host can send packet to controller * notify_host_recv: notify host that controller has packet send to host */ typedef struct vhci_host_callback { - void (*notify_host_send_available)(void); int (*notify_host_recv)(uint8_t *data, uint16_t len); } vhci_host_callback_t; -/** @brief: API_vhci_host_check_send_available +/** @brief API_vhci_host_check_send_available * used for check actively if the host can send packet to controller or not. - * return true for ready to send, false means cannot send packet + * @return true for ready to send, false means cannot send packet */ bool API_vhci_host_check_send_available(void); -/** @brief: API_vhci_host_send_packet +/** @brief API_vhci_host_send_packet * host send packet to controller - * param data is the packet point, the param len is the packet length - * return void + * @param data the packet point + *,@param len the packet length */ void API_vhci_host_send_packet(uint8_t *data, uint16_t len); -/** @brief: API_vhci_host_register_callback +/** @brief API_vhci_host_register_callback * register the vhci referece callback, the call back * struct defined by vhci_host_callback structure. - * param is the vhci_host_callback type variable + * @param callback vhci_host_callback type variable */ void API_vhci_host_register_callback(const vhci_host_callback_t *callback); diff --git a/components/driver/component.mk b/components/driver/component.mk index a19b131ef5..a208f6ae20 100644 --- a/components/driver/component.mk +++ b/components/driver/component.mk @@ -1,14 +1,8 @@ # # Component Makefile # -# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default, -# this will take the sources in this directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the SDK documents if you need to do this. -# COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := include/driver -include $(IDF_PATH)/make/component_common.mk diff --git a/components/driver/gpio.c b/components/driver/gpio.c index 320533e8d4..ddbcb352c0 100644 --- a/components/driver/gpio.c +++ b/components/driver/gpio.c @@ -1,368 +1,378 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// 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 -#include "esp_err.h" -#include "esp_intr.h" -#include "freertos/FreeRTOS.h" -#include "freertos/xtensa_api.h" -#include "driver/gpio.h" -#include "soc/soc.h" - -//TODO: move debug options to menuconfig -#define GPIO_DBG_ENABLE (0) -#define GPIO_WARNING_ENABLE (0) -#define GPIO_ERROR_ENABLE (0) -#define GPIO_INFO_ENABLE (0) -//DBG INFOR -#if GPIO_INFO_ENABLE -#define GPIO_INFO ets_printf -#else -#define GPIO_INFO(...) -#endif -#if GPIO_WARNING_ENABLE -#define GPIO_WARNING(format,...) do{\ - ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\ - ets_printf(format,##__VA_ARGS__);\ -}while(0) -#else -#define GPIO_WARNING(...) -#endif -#if GPIO_ERROR_ENABLE -#define GPIO_ERROR(format,...) do{\ - ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\ - ets_printf(format,##__VA_ARGS__);\ -}while(0) -#else -#define GPIO_ERROR(...) -#endif - -const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = { - GPIO_PIN_REG_0, - GPIO_PIN_REG_1, - GPIO_PIN_REG_2, - GPIO_PIN_REG_3, - GPIO_PIN_REG_4, - GPIO_PIN_REG_5, - GPIO_PIN_REG_6, - GPIO_PIN_REG_7, - GPIO_PIN_REG_8, - GPIO_PIN_REG_9, - GPIO_PIN_REG_10, - GPIO_PIN_REG_11, - GPIO_PIN_REG_12, - GPIO_PIN_REG_13, - GPIO_PIN_REG_14, - GPIO_PIN_REG_15, - GPIO_PIN_REG_16, - GPIO_PIN_REG_17, - GPIO_PIN_REG_18, - GPIO_PIN_REG_19, - 0, - GPIO_PIN_REG_21, - GPIO_PIN_REG_22, - GPIO_PIN_REG_23, - 0, - GPIO_PIN_REG_25, - GPIO_PIN_REG_26, - GPIO_PIN_REG_27, - 0, - 0, - 0, - 0, - GPIO_PIN_REG_32, - GPIO_PIN_REG_33, - GPIO_PIN_REG_34, - GPIO_PIN_REG_35, - GPIO_PIN_REG_36, - GPIO_PIN_REG_37, - GPIO_PIN_REG_38, - GPIO_PIN_REG_39 -}; - -static int is_valid_gpio(int gpio_num) -{ - if(gpio_num >= GPIO_PIN_COUNT || GPIO_PIN_MUX_REG[gpio_num] == 0) { - GPIO_ERROR("GPIO io_num=%d does not exist\n",gpio_num); - return 0; - } - return 1; -} - -esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type) -{ - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - if(intr_type >= GPIO_INTR_MAX) { - GPIO_ERROR("Unknown GPIO intr:%u\n",intr_type); - return ESP_ERR_INVALID_ARG; - } - GPIO.pin[gpio_num].int_type = intr_type; - return ESP_OK; -} - -esp_err_t gpio_intr_enable(gpio_num_t gpio_num) -{ - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - if(xPortGetCoreID() == 0) { - GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr - } else { - GPIO.pin[gpio_num].int_ena = GPIO_APP_CPU_INTR_ENA; //enable pro cpu intr - } - return ESP_OK; -} - -esp_err_t gpio_intr_disable(gpio_num_t gpio_num) -{ - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - GPIO.pin[gpio_num].int_ena = 0; //disable GPIO intr - return ESP_OK; -} - -static esp_err_t gpio_output_disable(gpio_num_t gpio_num) -{ - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - if(gpio_num < 32) { - GPIO.enable_w1tc = (0x1 << gpio_num); - } else { - GPIO.enable1_w1tc.data = (0x1 << (gpio_num - 32)); - } - return ESP_OK; -} - -static esp_err_t gpio_output_enable(gpio_num_t gpio_num) -{ - if(gpio_num >= 34) { - GPIO_ERROR("io_num=%d can only be input\n",gpio_num); - return ESP_ERR_INVALID_ARG; - } - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - if(gpio_num < 32) { - GPIO.enable_w1ts = (0x1 << gpio_num); - } else { - GPIO.enable1_w1ts.data = (0x1 << (gpio_num - 32)); - } - return ESP_OK; -} - -esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level) -{ - if(!GPIO_IS_VALID_GPIO(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - if(level) { - if(gpio_num < 32) { - GPIO.out_w1ts = (1 << gpio_num); - } else { - GPIO.out1_w1ts.data = (1 << (gpio_num - 32)); - } - } else { - if(gpio_num < 32) { - GPIO.out_w1tc = (1 << gpio_num); - } else { - GPIO.out1_w1tc.data = (1 << (gpio_num - 32)); - } - } - return ESP_OK; -} - -int gpio_get_level(gpio_num_t gpio_num) -{ - if(gpio_num < 32) { - return (GPIO.in >> gpio_num) & 0x1; - } else { - return (GPIO.in1.data >> (gpio_num - 32)) & 0x1; - } -} - -esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull) -{ - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - esp_err_t ret = ESP_OK; - switch(pull) { - case GPIO_PULLUP_ONLY: - PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]); - PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]); - break; - case GPIO_PULLDOWN_ONLY: - PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]); - PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]); - break; - case GPIO_PULLUP_PULLDOWN: - PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]); - PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]); - break; - case GPIO_FLOATING: - PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]); - PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]); - break; - default: - GPIO_ERROR("Unknown pull up/down mode,gpio_num=%u,pull=%u\n",gpio_num,pull); - ret = ESP_ERR_INVALID_ARG; - break; - } - return ret; -} - -esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode) -{ - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - if(gpio_num >= 34 && (mode & (GPIO_MODE_DEF_OUTPUT))) { - GPIO_ERROR("io_num=%d can only be input\n",gpio_num); - return ESP_ERR_INVALID_ARG; - } - esp_err_t ret = ESP_OK; - if(mode & GPIO_MODE_DEF_INPUT) { - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); - } else { - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); - } - if(mode & GPIO_MODE_DEF_OUTPUT) { - if(gpio_num < 32) { - GPIO.enable_w1ts = (0x1 << gpio_num); - } else { - GPIO.enable1_w1ts.data = (0x1 << (gpio_num - 32)); - } - } else { - if(gpio_num < 32) { - GPIO.enable_w1tc = (0x1 << gpio_num); - } else { - GPIO.enable1_w1tc.data = (0x1 << (gpio_num - 32)); - } - } - if(mode & GPIO_MODE_DEF_OD) { - GPIO.pin[gpio_num].pad_driver = 1; - } else { - GPIO.pin[gpio_num].pad_driver = 0; - } - return ret; -} - -esp_err_t gpio_config(gpio_config_t *pGPIOConfig) -{ - uint64_t gpio_pin_mask = (pGPIOConfig->pin_bit_mask); - uint32_t io_reg = 0; - uint32_t io_num = 0; - uint64_t bit_valid = 0; - if(pGPIOConfig->pin_bit_mask == 0 || pGPIOConfig->pin_bit_mask >= (((uint64_t) 1) << GPIO_PIN_COUNT)) { - GPIO_ERROR("GPIO_PIN mask error \n"); - return ESP_ERR_INVALID_ARG; - } - if((pGPIOConfig->mode) & (GPIO_MODE_DEF_OUTPUT)) { - //GPIO 34/35/36/37/38/39 can only be used as input mode; - if((gpio_pin_mask & ( GPIO_SEL_34 | GPIO_SEL_35 | GPIO_SEL_36 | GPIO_SEL_37 | GPIO_SEL_38 | GPIO_SEL_39))) { - GPIO_ERROR("GPIO34-39 can only be used as input mode\n"); - return ESP_ERR_INVALID_ARG; - } - } - do { - io_reg = GPIO_PIN_MUX_REG[io_num]; - if(((gpio_pin_mask >> io_num) & BIT(0)) && io_reg) { - GPIO_INFO("Gpio%02d |Mode:",io_num); - if((pGPIOConfig->mode) & GPIO_MODE_DEF_INPUT) { - GPIO_INFO("INPUT "); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_num]); - } else { - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[io_num]); - } - if((pGPIOConfig->mode) & GPIO_MODE_DEF_OD) { - GPIO_INFO("OD "); - GPIO.pin[io_num].pad_driver = 1; /*0x01 Open-drain */ - } else { - GPIO.pin[io_num].pad_driver = 0; /*0x00 Normal gpio output */ - } - if((pGPIOConfig->mode) & GPIO_MODE_DEF_OUTPUT) { - GPIO_INFO("OUTPUT "); - gpio_output_enable(io_num); - } else { - gpio_output_disable(io_num); - } - GPIO_INFO("|"); - if(pGPIOConfig->pull_up_en) { - GPIO_INFO("PU "); - PIN_PULLUP_EN(io_reg); - } else { - PIN_PULLUP_DIS(io_reg); - } - if(pGPIOConfig->pull_down_en) { - GPIO_INFO("PD "); - PIN_PULLDWN_EN(io_reg); - } else { - PIN_PULLDWN_DIS(io_reg); - } - GPIO_INFO("Intr:%d |\n",pGPIOConfig->intr_type); - gpio_set_intr_type(io_num, pGPIOConfig->intr_type); - if(pGPIOConfig->intr_type) { - gpio_intr_enable(io_num); - } else { - gpio_intr_disable(io_num); - } - PIN_FUNC_SELECT(io_reg, PIN_FUNC_GPIO); /*function number 2 is GPIO_FUNC for each pin */ - } else if(bit_valid && (io_reg == 0)) { - GPIO_WARNING("io_num=%d does not exist\n",io_num); - } - io_num++; - } while(io_num < GPIO_PIN_COUNT); - return ESP_OK; -} - -esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg) -{ - if(fn == NULL) { - return ESP_ERR_INVALID_ARG; - } - ESP_INTR_DISABLE(gpio_intr_num); - intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num); - xt_set_interrupt_handler(gpio_intr_num, fn, arg); - ESP_INTR_ENABLE(gpio_intr_num); - return ESP_OK; -} - -/*only level interrupt can be used for wake-up function*/ -esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type) -{ - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - esp_err_t ret = ESP_OK; - if((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) { - GPIO.pin[gpio_num].int_type = intr_type; - GPIO.pin[gpio_num].wakeup_enable = 0x1; - } else { - GPIO_ERROR("GPIO wakeup only support Level mode,but edge mode set. gpio_num:%u\n",gpio_num); - ret = ESP_ERR_INVALID_ARG; - } - return ret; -} - -esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num) -{ - if(!is_valid_gpio(gpio_num)) { - return ESP_ERR_INVALID_ARG; - } - GPIO.pin[gpio_num].wakeup_enable = 0; - return ESP_OK; -} +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include "esp_err.h" +#include "esp_intr.h" +#include "freertos/FreeRTOS.h" +#include "freertos/xtensa_api.h" +#include "driver/gpio.h" +#include "soc/soc.h" +#include "esp_log.h" + +static const char* GPIO_TAG = "GPIO"; +#define GPIO_CHECK(a, str, ret_val) if (!(a)) { \ + ESP_LOGE(GPIO_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ + return (ret_val); \ + } + +const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = { + GPIO_PIN_REG_0, + GPIO_PIN_REG_1, + GPIO_PIN_REG_2, + GPIO_PIN_REG_3, + GPIO_PIN_REG_4, + GPIO_PIN_REG_5, + GPIO_PIN_REG_6, + GPIO_PIN_REG_7, + GPIO_PIN_REG_8, + GPIO_PIN_REG_9, + GPIO_PIN_REG_10, + GPIO_PIN_REG_11, + GPIO_PIN_REG_12, + GPIO_PIN_REG_13, + GPIO_PIN_REG_14, + GPIO_PIN_REG_15, + GPIO_PIN_REG_16, + GPIO_PIN_REG_17, + GPIO_PIN_REG_18, + GPIO_PIN_REG_19, + 0, + GPIO_PIN_REG_21, + GPIO_PIN_REG_22, + GPIO_PIN_REG_23, + 0, + GPIO_PIN_REG_25, + GPIO_PIN_REG_26, + GPIO_PIN_REG_27, + 0, + 0, + 0, + 0, + GPIO_PIN_REG_32, + GPIO_PIN_REG_33, + GPIO_PIN_REG_34, + GPIO_PIN_REG_35, + GPIO_PIN_REG_36, + GPIO_PIN_REG_37, + GPIO_PIN_REG_38, + GPIO_PIN_REG_39 +}; + +const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT]={ + {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M}, + {PERIPHS_IO_MUX_U0TXD_U, FUN_PU, FUN_PD}, + {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M}, + {PERIPHS_IO_MUX_U0RXD_U, FUN_PU, FUN_PD}, + {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M}, + {PERIPHS_IO_MUX_GPIO5_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_CLK_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_DATA0_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_DATA1_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_DATA2_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_DATA3_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_CMD_U, FUN_PU, FUN_PD}, + {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M}, + {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M}, + {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M}, + {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M}, + {PERIPHS_IO_MUX_GPIO16_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO17_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO18_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO19_U, FUN_PU, FUN_PD}, + {0,0,0}, + {PERIPHS_IO_MUX_GPIO21_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO22_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO23_U, FUN_PU, FUN_PD}, + {0,0,0}, + {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M}, + {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M}, + {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M}, + {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M}, + {PERIPHS_IO_MUX_GPIO34_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO35_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO36_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO37_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO38_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO39_U, FUN_PU, FUN_PD} +}; + + +esp_err_t gpio_pullup_en(gpio_num_t gpio_num) { + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + return ESP_OK; +} + +esp_err_t gpio_pullup_dis(gpio_num_t gpio_num) { + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + return ESP_OK; +} + +esp_err_t gpio_pulldown_en(gpio_num_t gpio_num) { + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); + return ESP_OK; +} + +esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num) { + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); + return ESP_OK; +} + +esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(intr_type < GPIO_INTR_MAX, "GPIO interrupt type error", ESP_ERR_INVALID_ARG); + GPIO.pin[gpio_num].int_type = intr_type; + return ESP_OK; +} + +esp_err_t gpio_intr_enable(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + if(xPortGetCoreID() == 0) { + GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr + } else { + GPIO.pin[gpio_num].int_ena = GPIO_APP_CPU_INTR_ENA; //enable pro cpu intr + } + return ESP_OK; +} + +esp_err_t gpio_intr_disable(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO.pin[gpio_num].int_ena = 0; //disable GPIO intr + return ESP_OK; +} + +static esp_err_t gpio_output_disable(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + if(gpio_num < 32) { + GPIO.enable_w1tc = (0x1 << gpio_num); + } else { + GPIO.enable1_w1tc.data = (0x1 << (gpio_num - 32)); + } + return ESP_OK; +} + +static esp_err_t gpio_output_enable(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG); + if(gpio_num < 32) { + GPIO.enable_w1ts = (0x1 << gpio_num); + } else { + GPIO.enable1_w1ts.data = (0x1 << (gpio_num - 32)); + } + return ESP_OK; +} + +esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + if(level) { + if(gpio_num < 32) { + GPIO.out_w1ts = (1 << gpio_num); + } else { + GPIO.out1_w1ts.data = (1 << (gpio_num - 32)); + } + } else { + if(gpio_num < 32) { + GPIO.out_w1tc = (1 << gpio_num); + } else { + GPIO.out1_w1tc.data = (1 << (gpio_num - 32)); + } + } + return ESP_OK; +} + +int gpio_get_level(gpio_num_t gpio_num) +{ + if(gpio_num < 32) { + return (GPIO.in >> gpio_num) & 0x1; + } else { + return (GPIO.in1.data >> (gpio_num - 32)) & 0x1; + } +} + +esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(pull <= GPIO_FLOATING, "GPIO pull mode error", ESP_ERR_INVALID_ARG); + esp_err_t ret = ESP_OK; + switch(pull) { + case GPIO_PULLUP_ONLY: + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); + break; + case GPIO_PULLDOWN_ONLY: + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); + break; + case GPIO_PULLUP_PULLDOWN: + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); + break; + case GPIO_FLOATING: + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); + break; + default: + ESP_LOGE(GPIO_TAG, "Unknown pull up/down mode,gpio_num=%u,pull=%u",gpio_num,pull); + ret = ESP_ERR_INVALID_ARG; + break; + } + return ret; +} + +esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + if(gpio_num >= 34 && (mode & (GPIO_MODE_DEF_OUTPUT))) { + ESP_LOGE(GPIO_TAG, "io_num=%d can only be input",gpio_num); + return ESP_ERR_INVALID_ARG; + } + esp_err_t ret = ESP_OK; + if(mode & GPIO_MODE_DEF_INPUT) { + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); + } else { + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]); + } + if(mode & GPIO_MODE_DEF_OUTPUT) { + if(gpio_num < 32) { + GPIO.enable_w1ts = (0x1 << gpio_num); + } else { + GPIO.enable1_w1ts.data = (0x1 << (gpio_num - 32)); + } + } else { + if(gpio_num < 32) { + GPIO.enable_w1tc = (0x1 << gpio_num); + } else { + GPIO.enable1_w1tc.data = (0x1 << (gpio_num - 32)); + } + } + if(mode & GPIO_MODE_DEF_OD) { + GPIO.pin[gpio_num].pad_driver = 1; + } else { + GPIO.pin[gpio_num].pad_driver = 0; + } + return ret; +} + +esp_err_t gpio_config(gpio_config_t *pGPIOConfig) +{ + uint64_t gpio_pin_mask = (pGPIOConfig->pin_bit_mask); + uint32_t io_reg = 0; + uint32_t io_num = 0; + uint8_t input_en = 0; + uint8_t output_en = 0; + uint8_t od_en = 0; + uint8_t pu_en = 0; + uint8_t pd_en = 0; + if(pGPIOConfig->pin_bit_mask == 0 || pGPIOConfig->pin_bit_mask >= (((uint64_t) 1) << GPIO_PIN_COUNT)) { + ESP_LOGE(GPIO_TAG, "GPIO_PIN mask error "); + return ESP_ERR_INVALID_ARG; + } + if((pGPIOConfig->mode) & (GPIO_MODE_DEF_OUTPUT)) { + //GPIO 34/35/36/37/38/39 can only be used as input mode; + if((gpio_pin_mask & ( GPIO_SEL_34 | GPIO_SEL_35 | GPIO_SEL_36 | GPIO_SEL_37 | GPIO_SEL_38 | GPIO_SEL_39))) { + ESP_LOGE(GPIO_TAG, "GPIO34-39 can only be used as input mode"); + return ESP_ERR_INVALID_ARG; + } + } + do { + io_reg = GPIO_PIN_MUX_REG[io_num]; + if(((gpio_pin_mask >> io_num) & BIT(0)) && io_reg) { + if((pGPIOConfig->mode) & GPIO_MODE_DEF_INPUT) { + input_en = 1; + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_num]); + } else { + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[io_num]); + } + if((pGPIOConfig->mode) & GPIO_MODE_DEF_OD) { + od_en = 1; + GPIO.pin[io_num].pad_driver = 1; /*0x01 Open-drain */ + } else { + GPIO.pin[io_num].pad_driver = 0; /*0x00 Normal gpio output */ + } + if((pGPIOConfig->mode) & GPIO_MODE_DEF_OUTPUT) { + output_en = 1; + gpio_output_enable(io_num); + } else { + gpio_output_disable(io_num); + } + if(pGPIOConfig->pull_up_en) { + pu_en = 1; + REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd); + } else { + REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd); + } + if(pGPIOConfig->pull_down_en) { + pd_en = 1; + REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd); + } else { + REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd); + } + ESP_LOGI(GPIO_TAG, "GPIO[%d]| InputEn: %d| OutputEn: %d| OpenDrain: %d| Pullup: %d| Pulldown: %d| Intr:%d ", io_num, input_en, output_en, od_en, pu_en, pd_en, pGPIOConfig->intr_type); + gpio_set_intr_type(io_num, pGPIOConfig->intr_type); + if(pGPIOConfig->intr_type) { + gpio_intr_enable(io_num); + } else { + gpio_intr_disable(io_num); + } + PIN_FUNC_SELECT(io_reg, PIN_FUNC_GPIO); /*function number 2 is GPIO_FUNC for each pin */ + } + io_num++; + } while(io_num < GPIO_PIN_COUNT); + return ESP_OK; +} + +esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg) +{ + GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG); + ESP_INTR_DISABLE(gpio_intr_num); + intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num); + xt_set_interrupt_handler(gpio_intr_num, fn, arg); + ESP_INTR_ENABLE(gpio_intr_num); + return ESP_OK; +} + +/*only level interrupt can be used for wake-up function*/ +esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + esp_err_t ret = ESP_OK; + if((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) { + GPIO.pin[gpio_num].int_type = intr_type; + GPIO.pin[gpio_num].wakeup_enable = 0x1; + } else { + ESP_LOGE(GPIO_TAG, "GPIO wakeup only support Level mode,but edge mode set. gpio_num:%u",gpio_num); + ret = ESP_ERR_INVALID_ARG; + } + return ret; +} + +esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO.pin[gpio_num].wakeup_enable = 0; + return ESP_OK; +} diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index 9b47c88e69..5dad11f2ff 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -20,6 +20,7 @@ #include "soc/gpio_struct.h" #include "soc/rtc_io_reg.h" #include "soc/io_mux_reg.h" +#include "soc/gpio_sig_map.h" #include "rom/gpio.h" #include "esp_attr.h" @@ -27,43 +28,43 @@ extern "C" { #endif -#define GPIO_SEL_0 (BIT(0)) /* Pin 0 selected */ -#define GPIO_SEL_1 (BIT(1)) /* Pin 1 selected */ -#define GPIO_SEL_2 (BIT(2)) /* Pin 2 selected */ -#define GPIO_SEL_3 (BIT(3)) /* Pin 3 selected */ -#define GPIO_SEL_4 (BIT(4)) /* Pin 4 selected */ -#define GPIO_SEL_5 (BIT(5)) /* Pin 5 selected */ -#define GPIO_SEL_6 (BIT(6)) /* Pin 6 selected */ -#define GPIO_SEL_7 (BIT(7)) /* Pin 7 selected */ -#define GPIO_SEL_8 (BIT(8)) /* Pin 8 selected */ -#define GPIO_SEL_9 (BIT(9)) /* Pin 9 selected */ -#define GPIO_SEL_10 (BIT(10)) /* Pin 10 selected */ -#define GPIO_SEL_11 (BIT(11)) /* Pin 11 selected */ -#define GPIO_SEL_12 (BIT(12)) /* Pin 12 selected */ -#define GPIO_SEL_13 (BIT(13)) /* Pin 13 selected */ -#define GPIO_SEL_14 (BIT(14)) /* Pin 14 selected */ -#define GPIO_SEL_15 (BIT(15)) /* Pin 15 selected */ -#define GPIO_SEL_16 (BIT(16)) /* Pin 16 selected */ -#define GPIO_SEL_17 (BIT(17)) /* Pin 17 selected */ -#define GPIO_SEL_18 (BIT(18)) /* Pin 18 selected */ -#define GPIO_SEL_19 (BIT(19)) /* Pin 19 selected */ +#define GPIO_SEL_0 (BIT(0)) /*!< Pin 0 selected */ +#define GPIO_SEL_1 (BIT(1)) /*!< Pin 1 selected */ +#define GPIO_SEL_2 (BIT(2)) /*!< Pin 2 selected */ +#define GPIO_SEL_3 (BIT(3)) /*!< Pin 3 selected */ +#define GPIO_SEL_4 (BIT(4)) /*!< Pin 4 selected */ +#define GPIO_SEL_5 (BIT(5)) /*!< Pin 5 selected */ +#define GPIO_SEL_6 (BIT(6)) /*!< Pin 6 selected */ +#define GPIO_SEL_7 (BIT(7)) /*!< Pin 7 selected */ +#define GPIO_SEL_8 (BIT(8)) /*!< Pin 8 selected */ +#define GPIO_SEL_9 (BIT(9)) /*!< Pin 9 selected */ +#define GPIO_SEL_10 (BIT(10)) /*!< Pin 10 selected */ +#define GPIO_SEL_11 (BIT(11)) /*!< Pin 11 selected */ +#define GPIO_SEL_12 (BIT(12)) /*!< Pin 12 selected */ +#define GPIO_SEL_13 (BIT(13)) /*!< Pin 13 selected */ +#define GPIO_SEL_14 (BIT(14)) /*!< Pin 14 selected */ +#define GPIO_SEL_15 (BIT(15)) /*!< Pin 15 selected */ +#define GPIO_SEL_16 (BIT(16)) /*!< Pin 16 selected */ +#define GPIO_SEL_17 (BIT(17)) /*!< Pin 17 selected */ +#define GPIO_SEL_18 (BIT(18)) /*!< Pin 18 selected */ +#define GPIO_SEL_19 (BIT(19)) /*!< Pin 19 selected */ -#define GPIO_SEL_21 (BIT(21)) /* Pin 21 selected */ -#define GPIO_SEL_22 (BIT(22)) /* Pin 22 selected */ -#define GPIO_SEL_23 (BIT(23)) /* Pin 23 selected */ +#define GPIO_SEL_21 (BIT(21)) /*!< Pin 21 selected */ +#define GPIO_SEL_22 (BIT(22)) /*!< Pin 22 selected */ +#define GPIO_SEL_23 (BIT(23)) /*!< Pin 23 selected */ -#define GPIO_SEL_25 (BIT(25)) /* Pin 25 selected */ -#define GPIO_SEL_26 (BIT(26)) /* Pin 26 selected */ -#define GPIO_SEL_27 (BIT(27)) /* Pin 27 selected */ +#define GPIO_SEL_25 (BIT(25)) /*!< Pin 25 selected */ +#define GPIO_SEL_26 (BIT(26)) /*!< Pin 26 selected */ +#define GPIO_SEL_27 (BIT(27)) /*!< Pin 27 selected */ -#define GPIO_SEL_32 ((uint64_t)(((uint64_t)1)<<32)) /* Pin 32 selected */ -#define GPIO_SEL_33 ((uint64_t)(((uint64_t)1)<<33)) /* Pin 33 selected */ -#define GPIO_SEL_34 ((uint64_t)(((uint64_t)1)<<34)) /* Pin 34 selected */ -#define GPIO_SEL_35 ((uint64_t)(((uint64_t)1)<<35)) /* Pin 35 selected */ -#define GPIO_SEL_36 ((uint64_t)(((uint64_t)1)<<36)) /* Pin 36 selected */ -#define GPIO_SEL_37 ((uint64_t)(((uint64_t)1)<<37)) /* Pin 37 selected */ -#define GPIO_SEL_38 ((uint64_t)(((uint64_t)1)<<38)) /* Pin 38 selected */ -#define GPIO_SEL_39 ((uint64_t)(((uint64_t)1)<<39)) /* Pin 39 selected */ +#define GPIO_SEL_32 ((uint64_t)(((uint64_t)1)<<32)) /*!< Pin 32 selected */ +#define GPIO_SEL_33 ((uint64_t)(((uint64_t)1)<<33)) /*!< Pin 33 selected */ +#define GPIO_SEL_34 ((uint64_t)(((uint64_t)1)<<34)) /*!< Pin 34 selected */ +#define GPIO_SEL_35 ((uint64_t)(((uint64_t)1)<<35)) /*!< Pin 35 selected */ +#define GPIO_SEL_36 ((uint64_t)(((uint64_t)1)<<36)) /*!< Pin 36 selected */ +#define GPIO_SEL_37 ((uint64_t)(((uint64_t)1)<<37)) /*!< Pin 37 selected */ +#define GPIO_SEL_38 ((uint64_t)(((uint64_t)1)<<38)) /*!< Pin 38 selected */ +#define GPIO_SEL_39 ((uint64_t)(((uint64_t)1)<<39)) /*!< Pin 39 selected */ #define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U #define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U @@ -116,223 +117,217 @@ extern const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT]; #define GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0)) //to decide whether it is a valid GPIO number #define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) ((GPIO_IS_VALID_GPIO(gpio_num)) && (gpio_num < 34)) //to decide whether it can be a valid GPIO number of output mode +typedef struct { + uint32_t reg; /*!< Register to modify to enable or disable pullups or pulldowns */ + uint32_t pu; /*!< Bit to set or clear in the above register to enable or disable the pullup, respectively */ + uint32_t pd; /*!< Bit to set or clear in the above register to enable or disable the pulldown, respectively */ +} gpio_pu_pd_desc_t; + + +/** + * Per-GPIO pullup/pulldown information + * On the ESP32, some GPIOs need their pullups and pulldowns enabled and disabled in the RTC + * peripheral instead of in the GPIO peripheral. This array documents for every GPIO what bit + * to set or clear. + * + * This array is non-static, so if you need a very quick way of toggling the pull-up/downs, you can just + * do e.g. REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); inline. + * + * ToDo: Functions using the contents of this array will do a read/modify/write on GPIO as well as RTC + * registers. We may need to look into muxes/locks for other code that accesses these RTC registers when we + * write drivers for the RTC stuff. + */ +extern const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT]; + + typedef enum { - GPIO_NUM_0 = 0, - GPIO_NUM_1 = 1, - GPIO_NUM_2 = 2, - GPIO_NUM_3 = 3, - GPIO_NUM_4 = 4, - GPIO_NUM_5 = 5, - GPIO_NUM_6 = 6, - GPIO_NUM_7 = 7, - GPIO_NUM_8 = 8, - GPIO_NUM_9 = 9, - GPIO_NUM_10 = 10, - GPIO_NUM_11 = 11, - GPIO_NUM_12 = 12, - GPIO_NUM_13 = 13, - GPIO_NUM_14 = 14, - GPIO_NUM_15 = 15, - GPIO_NUM_16 = 16, - GPIO_NUM_17 = 17, - GPIO_NUM_18 = 18, - GPIO_NUM_19 = 19, + GPIO_NUM_0 = 0, /*!< GPIO0, input and output */ + GPIO_NUM_1 = 1, /*!< GPIO1, input and output */ + GPIO_NUM_2 = 2, /*!< GPIO2, input and output */ + GPIO_NUM_3 = 3, /*!< GPIO3, input and output */ + GPIO_NUM_4 = 4, /*!< GPIO4, input and output */ + GPIO_NUM_5 = 5, /*!< GPIO5, input and output */ + GPIO_NUM_6 = 6, /*!< GPIO6, input and output */ + GPIO_NUM_7 = 7, /*!< GPIO7, input and output */ + GPIO_NUM_8 = 8, /*!< GPIO8, input and output */ + GPIO_NUM_9 = 9, /*!< GPIO9, input and output */ + GPIO_NUM_10 = 10, /*!< GPIO10, input and output */ + GPIO_NUM_11 = 11, /*!< GPIO11, input and output */ + GPIO_NUM_12 = 12, /*!< GPIO12, input and output */ + GPIO_NUM_13 = 13, /*!< GPIO13, input and output */ + GPIO_NUM_14 = 14, /*!< GPIO14, input and output */ + GPIO_NUM_15 = 15, /*!< GPIO15, input and output */ + GPIO_NUM_16 = 16, /*!< GPIO16, input and output */ + GPIO_NUM_17 = 17, /*!< GPIO17, input and output */ + GPIO_NUM_18 = 18, /*!< GPIO18, input and output */ + GPIO_NUM_19 = 19, /*!< GPIO19, input and output */ - GPIO_NUM_21 = 21, - GPIO_NUM_22 = 22, - GPIO_NUM_23 = 23, + GPIO_NUM_21 = 21, /*!< GPIO21, input and output */ + GPIO_NUM_22 = 22, /*!< GPIO22, input and output */ + GPIO_NUM_23 = 23, /*!< GPIO23, input and output */ - GPIO_NUM_25 = 25, - GPIO_NUM_26 = 26, - GPIO_NUM_27 = 27, + GPIO_NUM_25 = 25, /*!< GPIO25, input and output */ + GPIO_NUM_26 = 26, /*!< GPIO26, input and output */ + GPIO_NUM_27 = 27, /*!< GPIO27, input and output */ - GPIO_NUM_32 = 32, - GPIO_NUM_33 = 33, - GPIO_NUM_34 = 34, /*input mode only */ - GPIO_NUM_35 = 35, /*input mode only */ - GPIO_NUM_36 = 36, /*input mode only */ - GPIO_NUM_37 = 37, /*input mode only */ - GPIO_NUM_38 = 38, /*input mode only */ - GPIO_NUM_39 = 39, /*input mode only */ + GPIO_NUM_32 = 32, /*!< GPIO32, input and output */ + GPIO_NUM_33 = 33, /*!< GPIO32, input and output */ + GPIO_NUM_34 = 34, /*!< GPIO34, input mode only */ + GPIO_NUM_35 = 35, /*!< GPIO35, input mode only */ + GPIO_NUM_36 = 36, /*!< GPIO36, input mode only */ + GPIO_NUM_37 = 37, /*!< GPIO37, input mode only */ + GPIO_NUM_38 = 38, /*!< GPIO38, input mode only */ + GPIO_NUM_39 = 39, /*!< GPIO39, input mode only */ } gpio_num_t; typedef enum { - GPIO_INTR_DISABLE = 0, /* disable GPIO interrupt */ - GPIO_INTR_POSEDGE = 1, /* GPIO interrupt type : rising edge */ - GPIO_INTR_NEGEDGE = 2, /* GPIO interrupt type : falling edge */ - GPIO_INTR_ANYEDGE = 3, /* GPIO interrupt type : both rising and falling edge */ - GPIO_INTR_LOW_LEVEL = 4, /* GPIO interrupt type : input low level trigger */ - GPIO_INTR_HIGH_LEVEL = 5, /* GPIO interrupt type : input high level trigger */ + GPIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */ + GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */ + GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */ + GPIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */ + GPIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */ + GPIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */ GPIO_INTR_MAX, } gpio_int_type_t; typedef enum { - GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /* GPIO mode : input only */ - GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /* GPIO mode : output only mode */ - GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /* GPIO mode : output only with open-drain mode */ - GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /* GPIO mode : output and input with open-drain mode*/ - GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)), /* GPIO mode : output and input mode */ + GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /*!< GPIO mode : input only */ + GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /*!< GPIO mode : output only mode */ + GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /*!< GPIO mode : output only with open-drain mode */ + GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /*!< GPIO mode : output and input with open-drain mode*/ + GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)), /*!< GPIO mode : output and input mode */ } gpio_mode_t; typedef enum { - GPIO_PULLUP_DISABLE = 0x0, /* disable GPIO pull-up resistor */ - GPIO_PULLUP_ENABLE = 0x1, /* enable GPIO pull-up resistor */ + GPIO_PULLUP_DISABLE = 0x0, /*!< Disable GPIO pull-up resistor */ + GPIO_PULLUP_ENABLE = 0x1, /*!< Enable GPIO pull-up resistor */ } gpio_pullup_t; typedef enum { - GPIO_PULLDOWN_DISABLE = 0x0, /* disable GPIO pull-down resistor */ - GPIO_PULLDOWN_ENABLE = 0x1, /* enable GPIO pull-down resistor */ + GPIO_PULLDOWN_DISABLE = 0x0, /*!< Disable GPIO pull-down resistor */ + GPIO_PULLDOWN_ENABLE = 0x1, /*!< Enable GPIO pull-down resistor */ } gpio_pulldown_t; typedef struct { - uint64_t pin_bit_mask; /* GPIO pin: set with bit mask, each bit maps to a GPIO */ - gpio_mode_t mode; /* GPIO mode: set input/output mode */ - gpio_pullup_t pull_up_en; /* GPIO pull-up */ - gpio_pulldown_t pull_down_en; /* GPIO pull-down */ - gpio_int_type_t intr_type; /* GPIO interrupt type */ + uint64_t pin_bit_mask; /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */ + gpio_mode_t mode; /*!< GPIO mode: set input/output mode */ + gpio_pullup_t pull_up_en; /*!< GPIO pull-up */ + gpio_pulldown_t pull_down_en; /*!< GPIO pull-down */ + gpio_int_type_t intr_type; /*!< GPIO interrupt type */ } gpio_config_t; typedef enum { - GPIO_LOW_LEVEL = 0, - GPIO_HIGH_LEVEL = 1, - GPIO_LEVEL_ERR, -} gpio_level_t; - -typedef enum { - GPIO_PULLUP_ONLY, /* Pad pull up */ - GPIO_PULLDOWN_ONLY, /* Pad pull down */ - GPIO_PULLUP_PULLDOWN, /* Pad pull up + pull down*/ - GPIO_FLOATING, /* Pad floating */ + GPIO_PULLUP_ONLY, /*!< Pad pull up */ + GPIO_PULLDOWN_ONLY, /*!< Pad pull down */ + GPIO_PULLUP_PULLDOWN, /*!< Pad pull up + pull down*/ + GPIO_FLOATING, /*!< Pad floating */ } gpio_pull_mode_t; typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num); -/** \defgroup Driver_APIs Driver APIs - * @brief Driver APIs - */ - -/** @addtogroup Driver_APIs - * @{ - */ - -/** \defgroup GPIO_Driver_APIs GPIO Driver APIs - * @brief GPIO APIs - */ - -/** @addtogroup GPIO_Driver_APIs - * @{ - */ - /** - * @brief GPIO common configuration + * @brief GPIO common configuration * - * Use this Function ,Configure GPIO's Mode,pull-up,PullDown,IntrType + * Configure GPIO's Mode,pull-up,PullDown,IntrType * - * @parameter[in] pGPIOConfig - * pGPIOConfig.pin_bit_mask : Configure GPIO pins bits,set this parameter with bit mask. - * If you want to configure GPIO34 and GPIO16, pin_bit_mask=GPIO_Pin_16|GPIO_Pin_34; - * pGPIOConfig.mode : Configure GPIO mode,such as output ,input... - * pGPIOConfig.pull_up_en : Enable or Disable pull-up - * pGPIOConfig.pull_down_en : Enable or Disable pull-down - * pGPIOConfig.intr_type : Configure GPIO interrupt trigger type - * @return ESP_OK: success ; - * ESP_ERR_INVALID_ARG: parameter error - * ESP_FAIL : GPIO error + * @param pGPIOConfig Pointer to GPIO configure struct + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t gpio_config(gpio_config_t *pGPIOConfig); /** - * @brief GPIO set interrupt trigger type + * @brief GPIO set interrupt trigger type * - * @parameter[in] gpio_num : GPIO number. - * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @parameter[in] intr_type: interrupt type, select from gpio_int_type_t + * @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param intr_type Interrupt type, select from gpio_int_type_t * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type); /** - * @brief enable GPIO module interrupt signal + * @brief Enable GPIO module interrupt signal * - * @parameter[in] gpio_num : GPIO number. - * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to enable an interrupt on e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t gpio_intr_enable(gpio_num_t gpio_num); /** - * @brief disable GPIO module interrupt signal + * @brief Disable GPIO module interrupt signal * - * @parameter[in] gpio_num : GPIO number. - * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t gpio_intr_disable(gpio_num_t gpio_num); /** - * @brief GPIO set output level + * @brief GPIO set output level * - * @parameter[in] gpio_num : GPIO number. - * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @parameter[in] level : Output level. 0: low ; 1: high + * @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param level Output level. 0: low ; 1: high * - * @return ESP_OK : success - * ESP_FAIL : GPIO error + * @return + * - ESP_OK Success + * - GPIO_IS_VALID_GPIO GPIO number error * */ esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level); /** - * @brief GPIO get input level + * @brief GPIO get input level * - * @parameter[in] gpio_num : GPIO number. - * If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return 0 : the GPIO input level is 0 - * 1 : the GPIO input level is 1 + * @return + * - 0 the GPIO input level is 0 + * - 1 the GPIO input level is 1 * */ int gpio_get_level(gpio_num_t gpio_num); /** - * @brief GPIO set direction + * @brief GPIO set direction * * Configure GPIO direction,such as output_only,input_only,output_and_input * - * @parameter[in] gpio_num : Configure GPIO pins number,it should be GPIO number. - * If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @parameter[in] mode : Configure GPIO direction,such as output_only,input_only,... + * @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param mode GPIO direction * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG : fail - * ESP_FAIL : GPIO error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG GPIO error * */ esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode); /** - * @brief GPIO set pull + * @brief GPIO set pull * * User this Function,configure GPIO pull mode,such as pull-up,pull-down * - * @parameter[in] gpio_num : Configure GPIO pins number,it should be GPIO number. - * If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16); - * @parameter[in] pull : Configure GPIO pull up/down mode,such as pullup_only,pulldown_only,pullup_and_pulldown,... + * @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param pull GPIO pull up/down mode. * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG : fail - * ESP_FAIL : GPIO error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG : Parameter error * */ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); @@ -340,121 +335,187 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); /** * @brief enable GPIO wake-up function. * - * @param gpio_num_t gpio_num : GPIO number. + * @param gpio_num GPIO number. * - * @param gpio_int_type_t intr_type : only GPIO_INTR_LOLEVEL\GPIO_INTR_HILEVEL can be used + * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL\GPIO_INTR_HIGH_LEVEL can be used. * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type); /** - * @brief disable GPIO wake-up function. + * @brief Disable GPIO wake-up function. * - * @param gpio_num_t gpio_num: GPIO number + * @param gpio_num GPIO number * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num); /** * @brief register GPIO interrupt handler, the handler is an ISR. * The handler will be attached to the same CPU core that this function is running on. + * @note * Users should know that which CPU is running and then pick a INUM that is not used by system. * We can find the information of INUM and interrupt level in soc.h. - * TODO: to move INUM options to menu_config - * @parameter uint32_t gpio_intr_num : GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details - * @parameter void (* fn)(void* ) : interrupt handler function. - * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". - * @parameter void * arg : parameter for handler function * - * @return ESP_OK : success ; - * ESP_FAIL: gpio error + * @param gpio_intr_num GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details + * @param fn Interrupt handler function. + * + * @note + * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". + * + * @param arg Parameter for handler function + * + * @return + * - ESP_OK Success ; + * - ESP_ERR_INVALID_ARG GPIO error */ esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg); + + +/** + * @brief Enable pull-up on GPIO. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_pullup_en(gpio_num_t gpio_num); + +/** + * @brief Disable pull-up on GPIO. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_pullup_dis(gpio_num_t gpio_num); + +/** + * @brief Enable pull-down on GPIO. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_pulldown_en(gpio_num_t gpio_num); + +/** + * @brief Disable pull-down on GPIO. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num); + + /** * *************** ATTENTION ********************/ /** - * - * Each GPIO has its own separate configuration register, so we do not use - * a lock to serialize access to them. This works under the assumption that - * no situation will occur where two tasks try to configure the same GPIO - * pin simultaneously. It is up to the application developer to guarantee this. + *@attention + * Each GPIO has its own separate configuration register, so we do not use + * a lock to serialize access to them. This works under the assumption that + * no situation will occur where two tasks try to configure the same GPIO + * pin simultaneously. It is up to the application developer to guarantee this. */ - -/*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ */ -/* gpio_config_t io_conf; +/** + *----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ * + * @code{c} + * gpio_config_t io_conf; * io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt * io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode * io_conf.pin_bit_mask = GPIO_SEL_18 | GPIO_SEL_19; //bit mask of the pins that you want to set,e.g.GPIO18/19 * io_conf.pull_down_en = 0; //disable pull-down mode * io_conf.pull_up_en = 0; //disable pull-up mode * gpio_config(&io_conf); //configure GPIO with the given settings + * @endcode **/ -/*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ */ -/* io_conf.intr_type = GPIO_INTR_POSEDGE; //set posedge interrupt + +/** + *----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ * + * @code{c} + * io_conf.intr_type = GPIO_INTR_POSEDGE; //set posedge interrupt * io_conf.mode = GPIO_MODE_INPUT; //set as input * io_conf.pin_bit_mask = GPIO_SEL_4 | GPIO_SEL_5; //bit mask of the pins that you want to set, e.g.,GPIO4/5 * io_conf.pull_down_en = 0; //disable pull-down mode * io_conf.pull_up_en = 1; //enable pull-up mode * gpio_config(&io_conf); //configure GPIO with the given settings - *----------EXAMPLE TO SET ISR HANDLER ----------------------*/ -/* gpio_isr_register(18,gpio_intr_test,NULL); //hook the isr handler for GPIO interrupt - * //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system. - * //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt. - * //NOTE2:do not pick the INUM that already occupied by the system. - * //NOTE3:refer to soc.h to check which INUMs that can be used. - *-------------EXAMPLE OF HANDLER FUNCTION-------------------*/ -/*#include "esp_attr.h" + * @endcode + */ +/** + *----------EXAMPLE TO SET ISR HANDLER ---------------------- + * @code{c} + * //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system. + * gpio_isr_register(18,gpio_intr_test,NULL); //hook the isr handler for GPIO interrupt + * @endcode + * @note + * 1. user should arrange the INUMs that used, better not to use a same INUM for different interrupt. + * 2. do not pick the INUM that already occupied by the system. + * 3. refer to soc.h to check which INUMs that can be used. + */ +/** + *-------------EXAMPLE OF HANDLER FUNCTION-------------------* + * @code{c} + * #include "esp_attr.h" * void IRAM_ATTR gpio_intr_test(void* arg) - *{ - * //GPIO intr process - * ets_printf("in gpio_intr\n"); - * uint32_t gpio_num = 0; - * uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); //read status to get interrupt status for GPIO0-31 - * uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39 - * SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status); //Clear intr for gpio0-gpio31 - * SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39 - * do { - * if(gpio_num < 32) { - * if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31 - * ets_printf("Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num)); - * //This is an isr handler, you should post an event to process it in RTOS queue. - * } - * } else { - * if(gpio_intr_status_h & BIT(gpio_num - 32)) { - * ets_printf("Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num)); - * //This is an isr handler, you should post an event to process it in RTOS queue. - * } - * } - * } while(++gpio_num < GPIO_PIN_COUNT); - *} - *----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---*/ -/* gpio_config_t io_conf; - * io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt - * io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD; //set as output mode - * io_conf.pin_bit_mask = GPIO_SEL_21 | GPIO_SEL_22; //bit mask of the pins that you want to set,e.g.GPIO21/22 - * io_conf.pull_down_en = 0; //disable pull-down mode - * io_conf.pull_up_en = 1; //enable pull-up mode - * gpio_config(&io_conf); //configure GPIO with the given settings - * gpio_matrix_out(21, EXT_I2C_SCL_O_IDX, 0, 0); //set output signal for io_matrix - * gpio_matrix_out(22, EXT_I2C_SDA_O_IDX, 0, 0); //set output signal for io_matrix - * gpio_matrix_in( 22, EXT_I2C_SDA_I_IDX, 0); //set input signal for io_matrix + * { + * //GPIO intr process + * ets_printf("in gpio_intr\n"); + * uint32_t gpio_num = 0; + * uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); //read status to get interrupt status for GPIO0-31 + * uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39 + * SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status); //Clear intr for gpio0-gpio31 + * SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39 + * do { + * if(gpio_num < 32) { + * if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31 + * ets_printf("Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num)); + * //This is an isr handler, you should post an event to process it in RTOS queue. + * } + * } else { + * if(gpio_intr_status_h & BIT(gpio_num - 32)) { + * ets_printf("Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num)); + * //This is an isr handler, you should post an event to process it in RTOS queue. + * } + * } + * } while(++gpio_num < GPIO_PIN_COUNT); + * } + * @endcode + */ + +/** + *----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---* + * @code{c} + * gpio_config_t io_conf; + * io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt + * io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD; //set as output mode + * io_conf.pin_bit_mask = GPIO_SEL_21 | GPIO_SEL_22; //bit mask of the pins that you want to set,e.g.GPIO21/22 + * io_conf.pull_down_en = 0; //disable pull-down mode + * io_conf.pull_up_en = 1; //enable pull-up mode + * gpio_config(&io_conf); //configure GPIO with the given settings + * gpio_matrix_out(21, EXT_I2C_SCL_O_IDX, 0, 0); //set output signal for io_matrix + * gpio_matrix_out(22, EXT_I2C_SDA_O_IDX, 0, 0); //set output signal for io_matrix + * gpio_matrix_in( 22, EXT_I2C_SDA_I_IDX, 0); //set input signal for io_matrix + * @endcode * */ -/** - * @} - */ - -/** - * @} - */ - #ifdef __cplusplus } #endif diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index 79a6c7f9f3..3ab0ebff1e 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -30,68 +30,68 @@ extern "C" { #define LEDC_REF_CLK_HZ (1*1000000) typedef enum { - LEDC_HIGH_SPEED_MODE = 0, /*LEDC high speed speed_mode */ + LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */ //in this version, we only support high speed speed_mode. We will access low speed speed_mode later - //LEDC_LOW_SPEED_MODE, /*LEDC low speed speed_mode */ - LEDC_SPEED_MODE_MAX, + //LEDC_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */ + LEDC_SPEED_MODE_MAX, /*!< LEDC speed limit */ } ledc_mode_t; typedef enum { - LEDC_INTR_DISABLE = 0, /*Disable LEDC interrupt */ - LEDC_INTR_FADE_END, /*Enable LEDC interrupt */ + LEDC_INTR_DISABLE = 0, /*!< Disable LEDC interrupt */ + LEDC_INTR_FADE_END, /*!< Enable LEDC interrupt */ } ledc_intr_type_t; typedef enum { - LEDC_DUTY_DIR_DECREASE = 0, /*LEDC duty decrease direction */ - LEDC_DUTY_DIR_INCREASE = 1, /*LEDC duty increase direction */ + LEDC_DUTY_DIR_DECREASE = 0, /*!< LEDC duty decrease direction */ + LEDC_DUTY_DIR_INCREASE = 1, /*!< LEDC duty increase direction */ } ledc_duty_direction_t; typedef enum { - LEDC_REF_TICK = 0, /*LEDC timer clock divided from reference tick(1Mhz) */ - LEDC_APB_CLK, /*LEDC timer clock divided from APB clock(80Mhz)*/ + LEDC_REF_TICK = 0, /*!< LEDC timer clock divided from reference tick(1Mhz) */ + LEDC_APB_CLK, /*!< LEDC timer clock divided from APB clock(80Mhz)*/ } ledc_clk_src_t; typedef enum { - LEDC_TIMER_0 = 0, /*LEDC source timer TIMER0 */ - LEDC_TIMER_1, /*LEDC source timer TIMER1 */ - LEDC_TIMER_2, /*LEDC source timer TIMER2 */ - LEDC_TIMER_3, /*LEDC source timer TIMER3 */ + LEDC_TIMER_0 = 0, /*!< LEDC source timer TIMER0 */ + LEDC_TIMER_1, /*!< LEDC source timer TIMER1 */ + LEDC_TIMER_2, /*!< LEDC source timer TIMER2 */ + LEDC_TIMER_3, /*!< LEDC source timer TIMER3 */ } ledc_timer_t; typedef enum { - LEDC_CHANNEL_0 = 0, /*LEDC channel 0 */ - LEDC_CHANNEL_1, /*LEDC channel 1 */ - LEDC_CHANNEL_2, /*LEDC channel 2 */ - LEDC_CHANNEL_3, /*LEDC channel 3 */ - LEDC_CHANNEL_4, /*LEDC channel 4 */ - LEDC_CHANNEL_5, /*LEDC channel 5 */ - LEDC_CHANNEL_6, /*LEDC channel 6 */ - LEDC_CHANNEL_7, /*LEDC channel 7 */ + LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */ + LEDC_CHANNEL_1, /*!< LEDC channel 1 */ + LEDC_CHANNEL_2, /*!< LEDC channel 2 */ + LEDC_CHANNEL_3, /*!< LEDC channel 3 */ + LEDC_CHANNEL_4, /*!< LEDC channel 4 */ + LEDC_CHANNEL_5, /*!< LEDC channel 5 */ + LEDC_CHANNEL_6, /*!< LEDC channel 6 */ + LEDC_CHANNEL_7, /*!< LEDC channel 7 */ } ledc_channel_t; typedef enum { - LEDC_TIMER_10_BIT = 10, /*LEDC PWM depth 10Bit */ - LEDC_TIMER_11_BIT = 11, /*LEDC PWM depth 11Bit */ - LEDC_TIMER_12_BIT = 12, /*LEDC PWM depth 12Bit */ - LEDC_TIMER_13_BIT = 13, /*LEDC PWM depth 13Bit */ - LEDC_TIMER_14_BIT = 14, /*LEDC PWM depth 14Bit */ - LEDC_TIMER_15_BIT = 15, /*LEDC PWM depth 15Bit */ + LEDC_TIMER_10_BIT = 10, /*!< LEDC PWM depth 10Bit */ + LEDC_TIMER_11_BIT = 11, /*!< LEDC PWM depth 11Bit */ + LEDC_TIMER_12_BIT = 12, /*!< LEDC PWM depth 12Bit */ + LEDC_TIMER_13_BIT = 13, /*!< LEDC PWM depth 13Bit */ + LEDC_TIMER_14_BIT = 14, /*!< LEDC PWM depth 14Bit */ + LEDC_TIMER_15_BIT = 15, /*!< LEDC PWM depth 15Bit */ } ledc_timer_bit_t; typedef struct { - int gpio_num; /*the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/ - ledc_mode_t speed_mode; /*LEDC speed speed_mode, high-speed mode or low-speed mode*/ - ledc_channel_t channel; /*LEDC channel(0 - 7)*/ - ledc_intr_type_t intr_type; /*configure interrupt, Fade interrupt enable or Fade interrupt disable*/ - ledc_timer_t timer_sel; /*Select the timer source of channel (0 - 3)*/ - uint32_t duty; /*LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */ + int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/ + ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/ + ledc_channel_t channel; /*!< LEDC channel(0 - 7)*/ + ledc_intr_type_t intr_type; /*!< configure interrupt, Fade interrupt enable or Fade interrupt disable*/ + ledc_timer_t timer_sel; /*!< Select the timer source of channel (0 - 3)*/ + uint32_t duty; /*!< LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */ } ledc_channel_config_t; typedef struct { - ledc_mode_t speed_mode; /*LEDC speed speed_mode, high-speed mode or low-speed mode*/ - ledc_timer_bit_t bit_num; /*LEDC channel duty depth*/ - ledc_timer_t timer_num; /*The timer source of channel (0 - 3)*/ - uint32_t freq_hz; /*LEDC timer frequency(Hz)*/ + ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/ + ledc_timer_bit_t bit_num; /*!< LEDC channel duty depth*/ + ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3)*/ + uint32_t freq_hz; /*!< LEDC timer frequency(Hz)*/ } ledc_timer_config_t; @@ -100,15 +100,10 @@ typedef struct { * * User this Function, configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC depth * - * @param[in] ledc_channel_config_t - * ledc_channel_config_t.speed_mode : LEDC speed speed_mode - * ledc_channel_config_t.gpio_num : LEDC output gpio_num, if you want to use gpio16, ledc_channel_config_t.gpio_num = 16 - * ledc_channel_config_t.channel : LEDC channel(0 - 7) - * ledc_channel_config_t.intr_type : configure interrupt, Fade interrupt enable or Fade interrupt disable - * ledc_channel_config_t.timer_sel : Select the timer source of channel (0 - 3), high speed channel must bind with high speed timer. - * ledc_channel_config_t.duty : LEDC channel duty, the duty range is [0, (2**timer_bit_num) - 1], - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @param ledc_conf Pointer of LEDC channel configure struct + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf); @@ -118,14 +113,13 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf); * * User this Function, configure LEDC timer with the given source timer/frequency(Hz)/bit_num * - * @param[in] ledc_timer_config_t - * ledc_timer_config_t.speed_mode : LEDC speed speed_mode - * ledc_timer_config_t.timer_num : Select the timer source of channel (0 - 3) - * ledc_timer_config_t.freq_hz : LEDC channel frequency(Hz), - * ledc_timer_config_t.bit_num : LEDC channel duty depth - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error - * ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num. + * @param timer_conf Pointer of LEDC timer configure struct + * + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current bit_num. * */ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf); @@ -136,12 +130,13 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf); * Call this function to activate the LEDC updated parameters. * After ledc_set_duty, ledc_set_fade, we need to call this function to update the settings. * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); @@ -151,12 +146,13 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); * * Disable LEDC output, and set idle level * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level); @@ -165,27 +161,29 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl * * Set LEDC frequency(Hz) * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_num : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_num LEDC timer index(0-3), select from ledc_timer_t * - * @param[in] freq_hz : set the LEDC frequency + * @param freq_hz Set the LEDC frequency * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error - * ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num. + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current bit_num. */ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz); /** * @brief LEDC get channel frequency(Hz) * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_num : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_num LEDC timer index(0-3), select from ledc_timer_t * - * @return 0 : error - * others : current LEDC frequency + * @return + * - 0 error + * - Others Current LEDC frequency * */ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num); @@ -195,27 +193,29 @@ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num); * * Set LEDC duty, After the function calls the ledc_update_duty function, the function can take effect. * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * - * @param[in] duty : set the LEDC duty, the duty range is [0, (2**bit_num) - 1] + * @param duty Set the LEDC duty, the duty range is [0, (2**bit_num) - 1] * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty); /** * @brief LEDC get duty * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * * - * @return -1: parameter error - * other value: current LEDC duty + * @return + * - (-1) parameter error + * - Others Current LEDC duty * */ int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel); @@ -225,22 +225,23 @@ int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel); * * Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect. * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * - * @param[in] duty : set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1] + * @param duty Set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1] * - * @param[in] gradule_direction : set the direction of the gradient + * @param gradule_direction Set the direction of the gradient * - * @param[in] step_num : set the number of the gradient + * @param step_num Set the number of the gradient * - * @param[in] duty_cyle_num : set how many LEDC tick each time the gradient lasts + * @param duty_cyle_num Set how many LEDC tick each time the gradient lasts * - * @param[in] duty_scale : set gradient change amplitude + * @param duty_scale Set gradient change amplitude * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG : parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t gradule_direction, uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale); @@ -248,34 +249,37 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, /** * @brief register LEDC interrupt handler, the handler is an ISR. * The handler will be attached to the same CPU core that this function is running on. - * Users should know that which CPU is running and then pick a INUM that is not used by system. - * We can find the information of INUM and interrupt level in soc.h. - * TODO: to move INUM options to menu_config - * @param[in] uint32_t ledc_intr_num : LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details - * @param[in] void (* fn)(void* ) : interrupt handler function. - * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". - * @param[in] void * arg : parameter for handler function + * @note + * Users should know that which CPU is running and then pick a INUM that is not used by system. + * We can find the information of INUM and interrupt level in soc.h. + * @param ledc_intr_num LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details + * @param fn Interrupt handler function. + * @note + * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". + * @param arg Parameter for handler function * - * @return ESP_OK : success ; - * ESP_ERR_INVALID_ARG : function ptr error. + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Function pointer error. */ esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg); /** * @brief configure LEDC settings * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_sel : timer index(0-3), there are 4 timers in LEDC module + * @param timer_sel Timer index(0-3), there are 4 timers in LEDC module * - * @param[in] div_num : timer clock divide number, the timer clock is divided from the selected clock source + * @param div_num Timer clock divide number, the timer clock is divided from the selected clock source * - * @param[in] bit_num : the count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1) + * @param bit_num The count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1) * - * @param[in] clk_src : select LEDC source clock. + * @param clk_src Select LEDC source clock. * - * @return -1: parameter error - * other value: current LEDC duty + * @return + * - (-1) Parameter error + * - Other Current LEDC duty * */ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src); @@ -283,13 +287,14 @@ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_ /** * @brief reset LEDC timer * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * - * @return ESP_ERR_INVALID_ARG: parameter error - * ESP_OK: success + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_OK Success * */ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel); @@ -297,13 +302,14 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief pause LEDC timer counter * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * - * @return ESP_ERR_INVALID_ARG: parameter error - * ESP_OK: success + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_OK Success * */ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel); @@ -311,13 +317,14 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief pause LEDC timer resume * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * - * @return ESP_ERR_INVALID_ARG: parameter error - * ESP_OK: success + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_OK Success * */ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel); @@ -325,15 +332,16 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief bind LEDC channel with the selected timer * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel index(0-7), select from ledc_channel_t + * @param channel LEDC channel index(0-7), select from ledc_channel_t * - * @param[in] timer_idx : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_idx LEDC timer index(0-3), select from ledc_timer_t * * - * @return ESP_ERR_INVALID_ARG: parameter error - * ESP_OK: success + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_OK Success * */ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx); @@ -342,44 +350,56 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint * * * ----------------EXAMPLE OF LEDC SETTING --------------------- - * //1. enable LEDC - * periph_module_enable(PERIPH_LEDC_MODULE); //enable LEDC module, or you can not set any register of it. + * @code{c} + * //1. enable LEDC + * //enable LEDC module, or you can not set any register of it. + * periph_module_enable(PERIPH_LEDC_MODULE); + * @endcode * - * //2. set LEDC timer - * ledc_timer_config_t timer_conf = { - * .bit_num = LEDC_TIMER_12_BIT, //set timer counter bit number - * .freq_hz = 1000, //set frequency of pwm, here, 1000Hz - * .speed_mode = LEDC_HIGH_SPEED_MODE //timer mode, - * .timer_num = LEDC_TIMER_0, //timer number - * }; - * ledc_timer_config(&timer_conf); //setup timer. + * @code{c} + * //2. set LEDC timer + * ledc_timer_config_t timer_conf = { + * .bit_num = LEDC_TIMER_12_BIT, //set timer counter bit number + * .freq_hz = 1000, //set frequency of pwm, here, 1000Hz + * .speed_mode = LEDC_HIGH_SPEED_MODE, //timer mode, + * .timer_num = LEDC_TIMER_0, //timer number + * }; + * ledc_timer_config(&timer_conf); //setup timer. + * @endcode * - * //3. set LEDC channel - * ledc_channel_config_t ledc_conf = { - * .channel = LEDC_CHANNEL_0; //set LEDC channel 0 - * .duty = 1000; //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1) - * .gpio_num = 16; //GPIO number - * .intr_type = LEDC_INTR_FADE_END; //GPIO INTR TYPE, as an example, we enable fade_end interrupt here. - * .speed_mode = LEDC_HIGH_SPEED_MODE; //set LEDC mode, from ledc_mode_t - * .timer_sel = LEDC_TIMER_0; //set LEDC timer source, if different channel use one timer, the frequency and bit_num of these channels should be the same - * } - * ledc_channel_config(&ledc_conf); //setup the configuration + * @code{c} + * //3. set LEDC channel + * ledc_channel_config_t ledc_conf = { + * .channel = LEDC_CHANNEL_0; //set LEDC channel 0 + * .duty = 1000; //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1) + * .gpio_num = 16; //GPIO number + * .intr_type = LEDC_INTR_FADE_END; //GPIO INTR TYPE, as an example, we enable fade_end interrupt here. + * .speed_mode = LEDC_HIGH_SPEED_MODE; //set LEDC mode, from ledc_mode_t + * .timer_sel = LEDC_TIMER_0; //set LEDC timer source, if different channel use one timer, the frequency and bit_num of these channels should be the same + * } + * ledc_channel_config(&ledc_conf); //setup the configuration * * ----------------EXAMPLE OF SETTING DUTY --- ----------------- - * uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73) - * uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1) - * LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty. - * ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel); //after set duty, we need to call ledc_update_duty to update the settings. - * + * @code{c} + * uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73) + * uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1) + * LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty. + * ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel); //after set duty, we need to call ledc_update_duty to update the settings. + * @endcode * * ----------------EXAMPLE OF LEDC INTERRUPT ------------------ - * //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here. - * ledc_isr_register(18, ledc_isr_handler, NULL); //hook the isr handler for LEDC interrupt - * //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system. - * //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt source. - * //NOTE2:do not pick the INUM that already occupied by the system. - * //NOTE3:refer to soc.h to check which INUMs that can be used. + * @code{c} + * //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here. + * ledc_isr_register(18, ledc_isr_handler, NULL); //hook the isr handler for LEDC interrupt + * @endcode + * @note + * 1. the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system. + * 2. user should arrange the INUMs that used, better not to use a same INUM for different interrupt source. + * 3. do not pick the INUM that already occupied by the system. + * 4. refer to soc.h to check which INUMs that can be used. + * * ----------------EXAMPLE OF INTERRUPT HANDLER --------------- + * @code{c} * #include "esp_attr.h" * void IRAM_ATTR ledc_isr_handler(void* arg) //we should add 'IRAM_ATTR' attribution when we declare the isr function * { @@ -391,7 +411,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint * * LEDC.int_clr.val = intr_st; //clear LEDC interrupt status. * } - * + * @endcode * *--------------------------END OF EXAMPLE -------------------------- */ diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h new file mode 100644 index 0000000000..7dccf1666c --- /dev/null +++ b/components/driver/include/driver/uart.h @@ -0,0 +1,763 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _DRIVER_UART_H_ +#define _DRIVER_UART_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "soc/uart_reg.h" +#include "soc/uart_struct.h" +#include "esp_err.h" +#include "driver/periph_ctrl.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/xtensa_api.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/ringbuf.h" +#include + +#define UART_FIFO_LEN (128) /*< Length of the hardware FIFO buffers */ +#define UART_INTR_MASK 0x1ff +#define UART_LINE_INV_MASK (0x3f << 19) +#define UART_BITRATE_MAX 5000000 +#define UART_PIN_NO_CHANGE (-1) + +#define UART_INVERSE_DISABLE (0x0) /*!< Disable UART signal inverse*/ +#define UART_INVERSE_RXD (UART_RXD_INV_M) /*!< UART RXD input inverse*/ +#define UART_INVERSE_CTS (UART_CTS_INV_M) /*!< UART CTS input inverse*/ +#define UART_INVERSE_TXD (UART_TXD_INV_M) /*!< UART TXD output inverse*/ +#define UART_INVERSE_RTS (UART_RTS_INV_M) /*!< UART RTS output inverse*/ + +typedef enum { + UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/ + UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/ + UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/ + UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/ + UART_DATA_BITS_MAX = 0X4, +} uart_word_length_t; + +typedef enum { + UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/ + UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/ + UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/ + UART_STOP_BITS_MAX = 0x4, +} uart_stop_bits_t; + +typedef enum { + UART_NUM_0 = 0x0, /*!< UART base address 0x3ff40000*/ + UART_NUM_1 = 0x1, /*!< UART base address 0x3ff50000*/ + UART_NUM_2 = 0x2, /*!< UART base address 0x3ff6E000*/ + UART_NUM_MAX, +} uart_port_t; + +typedef enum { + UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/ + UART_PARITY_EVEN = 0x10, /*!< Enable UART even parity*/ + UART_PARITY_ODD = 0x11 /*!< Enable UART odd parity*/ +} uart_parity_t; + +typedef enum { + UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/ + UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/ + UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/ + UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/ + UART_HW_FLOWCTRL_MAX = 0x4, +} uart_hw_flowcontrol_t; + +typedef struct { + int baud_rate; /*!< UART baudrate*/ + uart_word_length_t data_bits; /*!< UART byte size*/ + uart_parity_t parity; /*!< UART parity mode*/ + uart_stop_bits_t stop_bits; /*!< UART stop bits*/ + uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode(cts/rts)*/ + uint8_t rx_flow_ctrl_thresh ; /*!< UART HW RTS threshold*/ +} uart_config_t; + +typedef struct { + uint32_t intr_enable_mask; /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/ + uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold(unit: time of sending one byte)*/ + uint8_t txfifo_empty_intr_thresh; /*!< UART TX empty interrupt threshold.*/ + uint8_t rxfifo_full_thresh; /*!< UART RX full interrupt threshold.*/ +} uart_intr_config_t; + +typedef enum { + UART_DATA, /*!< UART data event*/ + UART_BREAK, /*!< UART break event*/ + UART_BUFFER_FULL, /*!< UART RX buffer full event*/ + UART_FIFO_OVF, /*!< UART FIFO overflow event*/ + UART_FRAME_ERR, /*!< UART RX frame error event*/ + UART_PARITY_ERR, /*!< UART RX parity event*/ + UART_DATA_BREAK, /*!< UART TX data and break event*/ + UART_EVENT_MAX, /*!< UART event max index*/ +} uart_event_type_t; + +typedef struct { + uart_event_type_t type; /*!< UART event type */ + size_t size; /*!< UART data size for UART_DATA event*/ +} uart_event_t; + +/** + * @brief Set UART data bits. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param data_bit UART data bits + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit); + +/** + * @brief Get UART data bits. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_FAIL Parameter error + * - ESP_OK Success, result will be put in (*data_bit) + */ +esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit); + +/** + * @brief Set UART stop bits. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param bit_num UART stop bits + * + * @return + * - ESP_OK Success + * - ESP_FAIL Fail + */ +esp_err_t uart_set_stop_bits(uart_port_t uart_no, uart_stop_bits_t bit_num); + +/** + * @brief Set UART stop bits. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_FAIL Parameter error + * - ESP_OK Success, result will be put in (*stop_bit) + */ +esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit); + +/** + * @brief Set UART parity. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param parity_mode the enum of uart parity configuration + * + * @return + * - ESP_FAIL Parameter error + * - ESP_OK Success + */ +esp_err_t uart_set_parity(uart_port_t uart_no, uart_parity_t parity_mode); + +/** + * @brief Get UART parity mode. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_FAIL Parameter error + * - ESP_OK Success, result will be put in (*parity_mode) + * + */ +esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode); + +/** + * @brief Set UART baud rate. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param baud_rate UART baud-rate. + * + * @return + * - ESP_FAIL Parameter error + * - ESP_OK Success + */ +esp_err_t uart_set_baudrate(uart_port_t uart_no, uint32_t baud_rate); + +/** + * @brief Get UART bit-rate. + * + * @param uart_no: UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_FAIL Parameter error + * - ESP_OK Success, result will be put in (*baudrate) + * + */ +esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate); + +/** + * @brief Set UART line inverse mode + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param inverse_mask Choose the wires that need to be inversed. + * + * (inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR-OPERATION) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_set_line_inverse(uart_port_t uart_no, uint32_t inverse_mask); + +/** + * @brief Set hardware flow control. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param flow_ctrl Hardware flow control mode + * + * @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN) + * + * Only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set. + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_no, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh); + +/** + * @brief Get hardware flow control mode + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_FAIL Parameter error + * - ESP_OK Success, result will be put in (*flow_ctrl) + */ +esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl); + +/** + * @brief Clear UART interrupt status + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param clr_mask Bit mask of the status that to be cleared. + * + * (enable_mask should be chosen from the fields of register UART_INT_CLR_REG) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask); + +/** + * @brief Set UART interrupt enable + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param enable_mask Bit mask of the enable bits. + * + * (enable_mask should be chosen from the fields of register UART_INT_ENA_REG) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask); + +/** + * @brief Clear UART interrupt enable bits + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param disable_mask Bit mask of the disable bits. + * + * (disable_mask should be chosen from the fields of register UART_INT_ENA_REG) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask); + + +/** + * @brief Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_enable_rx_intr(uart_port_t uart_num); + +/** + * @brief Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_disable_rx_intr(uart_port_t uart_num); + +/** + * @brief Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_disable_tx_intr(uart_port_t uart_num); + +/** + * @brief Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param enable 1: enable; 0: disable + * + * @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh); + +/** +* @brief register UART interrupt handler(ISR). +* @note + * UART ISR handler will be attached to the same CPU core that this function is running on. + * Users should know that which CPU is running and then pick a INUM that is not used by system. + * We can find the information of INUM and interrupt level in soc.h. + * + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details + * + * @param fn Interrupt handler function. + * @attention + * The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now. + * @param arg parameter for handler function + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg); + +/** + * @brief Set UART pin number + * + * @note + * Internal signal can be output to multiple GPIO pads + * Only one GPIO pad can connect with input signal + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param tx_io_num UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. + * + * @param rx_io_num UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. + * + * @param rts_io_num UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. + * + * @param cts_io_num UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num); + +/** + * @brief UART set RTS level (before inverse) + * UART rx hardware flow control should not be set. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param level 1: RTS output low(active); 0: RTS output high(block) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_set_rts(uart_port_t uart_num, int level); + +/** + * @brief UART set DTR level (before inverse) + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param level 1: DTR output low; 0: DTR output high + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_set_dtr(uart_port_t uart_num, int level); + +/** +* @brief UART parameter configure + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param uart_config UART parameter settings + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config); + +/** +* @brief UART interrupt configure + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param intr_conf UART interrupt settings + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf); + +/** + * @brief Install UART driver. + * + * UART ISR handler will be attached to the same CPU core that this function is running on. + * Users should know that which CPU is running and then pick a INUM that is not used by system. + * We can find the information of INUM and interrupt level in soc.h. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param rx_buffer_size UART RX ring buffer size + * + * @param tx_buffer_size UART TX ring buffer size. + * + * If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out.. + * + * @param queue_size UART event queue size/depth. + * + * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details + * + * @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue. + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, int uart_intr_num, void* uart_queue); + +/** + * @brief Uninstall UART driver. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_driver_delete(uart_port_t uart_num); + +/** + * @brief Wait UART TX FIFO empty + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param ticks_to_wait Timeout, count in RTOS ticks + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + * - ESP_ERR_TIMEOUT Timeout + */ +esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait); + +/** + * @brief Send data to the UART port from a given buffer and length, + * This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full. + * @note + * This function should only be used when UART TX buffer is not enabled. + * + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param buffer data buffer address + * + * @param len data length to send + * + * @return + * - (-1) Parameter error + * - OTHERS(>=0) The number of data that pushed to the TX FIFO + */ +int uart_tx_chars(uart_port_t uart_no, const char* buffer, uint32_t len); + +/** + * @brief Send data to the UART port from a given buffer and length, + * + * If parameter tx_buffer_size is set to zero: + * This function will not return until all the data have been sent out, or at least pushed into TX FIFO. + * + * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer, + * then, UART ISR will move data from ring buffer to TX FIFO gradually. + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param src data buffer address + * + * @param size data length to send + * + * @return + * - (-1) Parameter error + * - OTHERS(>=0) The number of data that pushed to the TX FIFO + */ +int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size); + +/** + * @brief Send data to the UART port from a given buffer and length, + * + * If parameter tx_buffer_size is set to zero: + * This function will not return until all the data and the break signal have been sent out. + * After all data send out, send a break signal. + * + * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer, + * then, UART ISR will move data from ring buffer to TX FIFO gradually. + * After all data send out, send a break signal. + * + * + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param src data buffer address + * + * @param size data length to send + * + * @param brk_len break signal length (unit: one bit's time@current_baudrate) + * + * @return + * - (-1) Parameter error + * - OTHERS(>=0) The number of data that pushed to the TX FIFO + */ + +int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len); + +/** +* @brief UART read bytes from UART buffer + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @param buf pointer to the buffer. + * + * @param length data length + * + * @param ticks_to_wait sTimeout, count in RTOS ticks + * + * + * @return + * - (-1) Error + * - Others return a char data from uart fifo. + */ +int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait); + +/** + * @brief UART ring buffer flush + * + * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_flush(uart_port_t uart_num); + +/***************************EXAMPLE********************************** + * + * + * ----------------EXAMPLE OF UART SETTING --------------------- + * @code{c} + * //1. Setup UART + * #include "freertos/queue.h" + * #define UART_INTR_NUM 17 //choose one interrupt number from soc.h + * //a. Set UART parameter + * int uart_num = 0; //uart port number + * uart_config_t uart_config = { + * .baud_rate = UART_BITRATE_115200, //baudrate + * .data_bits = UART_DATA_8_BITS, //data bit mode + * .parity = UART_PARITY_DISABLE, //parity mode + * .stop_bits = UART_STOP_BITS_1, //stop bit mode + * .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, //hardware flow control(cts/rts) + * .rx_flow_ctrl_thresh = 120, //flow control threshold + * }; + * uart_param_config(uart_num, &uart_config); + * //b1. Setup UART driver(with UART queue) + * QueueHandle_t uart_queue; + * //parameters here are just an example, tx buffer size is 2048 + * uart_driver_install(uart_num, 1024 * 2, 1024 * 2, 10, UART_INTR_NUM, &uart_queue); + * //b2. Setup UART driver(without UART queue) + * //parameters here are just an example, tx buffer size is 0 + * uart_driver_install(uart_num, 1024 * 2, 0, 10, UART_INTR_NUM, NULL); + *@endcode + *-----------------------------------------------------------------------------* + * @code{c} + * //2. Set UART pin + * //set UART pin, not needed if use default pins. + * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 15, 13); + * @endcode + *-----------------------------------------------------------------------------* + * @code{c} + * //3. Read data from UART. + * uint8_t data[128]; + * int length = 0; + * length = uart_read_bytes(uart_num, data, sizeof(data), 100); + * @endcode + *-----------------------------------------------------------------------------* + * @code{c} + * //4. Write data to UART. + * char* test_str = "This is a test string.\n" + * uart_write_bytes(uart_num, (const char*)test_str, strlen(test_str)); + * @endcode + *-----------------------------------------------------------------------------* + * @code{c} + * //5. Write data to UART, end with a break signal. + * uart_write_bytes_with_break(0, "test break\n",strlen("test break\n"), 100); + * @endcode + *-----------------------------------------------------------------------------* + * @code{c} + * //6. an example of echo test with hardware flow control on UART1 + * void uart_loop_back_test() + * { + * int uart_num = 1; + * uart_config_t uart_config = { + * .baud_rate = 115200, + * .data_bits = UART_DATA_8_BITS, + * .parity = UART_PARITY_DISABLE, + * .stop_bits = UART_STOP_BITS_1, + * .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, + * .rx_flow_ctrl_thresh = 122, + * }; + * //Configure UART1 parameters + * uart_param_config(uart_num, &uart_config); + * //Set UART1 pins(TX: IO16, RX: IO17, RTS: IO18, CTS: IO19) + * uart_set_pin(uart_num, 16, 17, 18, 19); + * //Install UART driver( We don't need an event queue here) + * uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, NULL, RINGBUF_TYPE_BYTEBUF); + * uint8_t data[1000]; + * while(1) { + * //Read data from UART + * int len = uart_read_bytes(uart_num, data, sizeof(data), 10); + * //Write data back to UART + * uart_write_bytes(uart_num, (const char*)data, len); + * } + * } + * @endcode + *-----------------------------------------------------------------------------* + * @code{c} + * //7. An example of using UART event queue on UART0. + * #include "freertos/queue.h" + * //A queue to handle UART event. + * QueueHandle_t uart0_queue; + * static const char *TAG = "uart_example"; + * void uart_task(void *pvParameters) + * { + * int uart_num = (int)pvParameters; + * uart_event_t event; + * uint8_t dtmp[1000]; + * for(;;) { + * //Waiting for UART event. + * if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) { + * ESP_LOGI(TAG, "uart[%d] event:", uart_num); + * switch(event.type) { + * memset(dtmp, 0, sizeof(dtmp)); + * //Event of UART receving data + * case UART_DATA: + * ESP_LOGI(TAG,"data, len: %d", event.size); + * int len = uart_read_bytes(uart_num, dtmp, event.size, 10); + * ESP_LOGI(TAG, "uart read: %d", len); + uart_write_bytes(uart_num, (const char*)dtmp, len); + * break; + * //Event of HW FIFO overflow detected + * case UART_FIFO_OVF: + * ESP_LOGI(TAG, "hw fifo overflow\n"); + * break; + * //Event of UART ring buffer full + * case UART_BUFFER_FULL: + * ESP_LOGI(TAG, "ring buffer full\n"); + * break; + * //Event of UART RX break detected + * case UART_BREAK: + * ESP_LOGI(TAG, "uart rx break\n"); + * break; + * //Event of UART parity check error + * case UART_PARITY_ERR: + * ESP_LOGI(TAG, "uart parity error\n"); + * break; + * //Event of UART frame error + * case UART_FRAME_ERR: + * ESP_LOGI(TAG, "uart frame error\n"); + * break; + * //Others + * default: + * ESP_LOGI(TAG, "uart event type: %d\n", event.type); + * break; + * } + * } + * } + * vTaskDelete(NULL); + * } + * + * void uart_queue_test() + * { + * int uart_num = 0; + * uart_config_t uart_config = { + * .baud_rate = 115200, + * .data_bits = UART_DATA_8_BITS, + * .parity = UART_PARITY_DISABLE, + * .stop_bits = UART_STOP_BITS_1, + * .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + * .rx_flow_ctrl_thresh = 122, + * }; + * //Set UART parameters + * uart_param_config(uart_num, &uart_config); + * //Set UART pins,(-1: default pin, no change.) + * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 15, 13); + * //Set UART log level + * esp_log_level_set(TAG, ESP_LOG_INFO); + * //Install UART driver, and get the queue. + * uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, &uart0_queue, RINGBUF_TYPE_BYTEBUF); + * //Create a task to handler UART event from ISR + * xTaskCreate(uart_task, "uTask", 2048*8, (void*)uart_num, 10, NULL); + * } + * @endcode + * + ***************************END OF EXAMPLE**********************************/ + +#ifdef __cplusplus +} +#endif + +#endif /*_DRIVER_UART_H_*/ diff --git a/components/driver/ledc.c b/components/driver/ledc.c index 386c93dfa6..41eb82cbdd 100644 --- a/components/driver/ledc.c +++ b/components/driver/ledc.c @@ -18,86 +18,19 @@ #include "freertos/xtensa_api.h" #include "soc/gpio_sig_map.h" #include "driver/ledc.h" +#include "esp_log.h" -//TODO: to use APIs in esp_log.h. -#define LEDC_DBG_WARING_ENABLE (0) -#define LEDC_DBG_ERROR_ENABLE (0) -#define LEDC_INFO_ENABLE (0) -#define LEDC_DBG_ENABLE (0) - -//DBG INFOR -#if LEDC_DBG_ENABLE -#define LEDC_DBG(format,...) do{\ - ets_printf("[dbg][%s#%u]",__FUNCTION__,__LINE__);\ - ets_printf(format,##__VA_ARGS__);\ -}while(0) -#else -#define LEDC_DBG(...) -#endif - -#if LEDC_INFO_ENABLE -#define LEDC_INFO(format,...) do{\ - ets_printf("[info][%s#%u]",__FUNCTION__,__LINE__);\ - ets_printf(format,##__VA_ARGS__);\ -}while(0) -#else -#define LEDC_INFO(...) -#endif - -#if LEDC_DBG_WARING_ENABLE -#define LEDC_WARING(format,...) do{\ - ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\ - ets_printf(format,##__VA_ARGS__);\ -}while(0) -#else -#define LEDC_WARING(...) -#endif -#if LEDC_DBG_ERROR_ENABLE -#define LEDC_ERROR(format,...) do{\ - ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\ - ets_printf(format,##__VA_ARGS__);\ -}while(0) -#else -#define LEDC_ERROR(...) -#endif - +static const char* LEDC_TAG = "LEDC"; static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED; - -static bool ledc_is_valid_channel(uint32_t channel) -{ - if(channel > LEDC_CHANNEL_7) { - LEDC_ERROR("LEDC CHANNEL ERR: %d\n",channel); - return false; - } - return true; -} - -static bool ledc_is_valid_mode(uint32_t mode) -{ - if(mode >= LEDC_SPEED_MODE_MAX) { - LEDC_ERROR("LEDC MODE ERR: %d\n",mode); - return false; - } - return true; -} - -static bool ledc_is_valid_timer(int timer) -{ - if(timer > LEDC_TIMER_3) { - LEDC_ERROR("LEDC TIMER ERR: %d\n", timer); - return false; - } - return true; -} +#define LEDC_CHECK(a, str, ret_val) if (!(a)) { \ + ESP_LOGE(LEDC_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ + return (ret_val); \ + } esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_timer(timer_sel)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.timer_group[speed_mode].timer[timer_sel].conf.div_num = div_num; LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src; @@ -125,12 +58,8 @@ static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, uint32_t channel_num, esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_timer(timer_idx)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(timer_idx <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx; portEXIT_CRITICAL(&ledc_spinlock); @@ -139,12 +68,8 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_timer(timer_sel)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 1; LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 0; @@ -154,12 +79,8 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel) esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_timer(timer_sel)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1; portEXIT_CRITICAL(&ledc_spinlock); @@ -168,12 +89,8 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel) esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_timer(timer_sel)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0; portEXIT_CRITICAL(&ledc_spinlock); @@ -182,9 +99,7 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel) static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); uint32_t value; uint32_t intr_type = type; portENTER_CRITICAL(&ledc_spinlock); @@ -200,9 +115,7 @@ static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg) { - if(fn == NULL) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(fn, "ledc isr null", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); ESP_INTR_DISABLE(ledc_intr_num); intr_matrix_set(xPortGetCoreID(), ETS_LEDC_INTR_SOURCE, ledc_intr_num); @@ -218,16 +131,13 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf) int bit_num = timer_conf->bit_num; int timer_num = timer_conf->timer_num; int speed_mode = timer_conf->speed_mode; - - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); if(freq_hz == 0 || bit_num == 0 || bit_num > LEDC_TIMER_15_BIT) { - LEDC_ERROR("freq_hz=%u bit_num=%u\n", freq_hz, bit_num); + ESP_LOGE(LEDC_TAG, "freq_hz=%u bit_num=%u", freq_hz, bit_num); return ESP_ERR_INVALID_ARG; } if(timer_num > LEDC_TIMER_3) { - LEDC_ERROR("Time Select %u\n", timer_num); + ESP_LOGE(LEDC_TAG, "Time Select %u", timer_num); return ESP_ERR_INVALID_ARG; } esp_err_t ret = ESP_OK; @@ -239,7 +149,7 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf) /*Selet the reference tick*/ div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision; if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) { - LEDC_ERROR("div param err,div_param=%u\n", div_param); + ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", (uint32_t)div_param); ret = ESP_FAIL; } timer_clk_src = LEDC_REF_TICK; @@ -254,6 +164,21 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf) return ret; } +esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel) +{ + LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO); + gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT); + if(speed_mode == LEDC_HIGH_SPEED_MODE) { + gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0); + } else { + + } + return ESP_OK; +} + esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf) { uint32_t speed_mode = ledc_conf->speed_mode; @@ -262,21 +187,10 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf) uint32_t timer_select = ledc_conf->timer_sel; uint32_t intr_type = ledc_conf->intr_type; uint32_t duty = ledc_conf->duty; - - if(!ledc_is_valid_channel(ledc_channel)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)) { - LEDC_ERROR("GPIO number error: IO%d\n ", gpio_num); - return ESP_ERR_INVALID_ARG; - } - if(timer_select > LEDC_TIMER_3) { - LEDC_ERROR("Time Select %u\n", timer_select); - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(timer_select <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG); esp_err_t ret = ESP_OK; /*set channel parameters*/ /* channel parameters decide how the waveform looks like in one period*/ @@ -288,7 +202,7 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf) ledc_bind_channel_timer(speed_mode, ledc_channel, timer_select); /*set interrupt type*/ ledc_enable_intr_type(speed_mode, ledc_channel, intr_type); - LEDC_INFO("LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u\n", + ESP_LOGI(LEDC_TAG, "LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u", ledc_channel, gpio_num, duty, timer_select ); /*set LEDC signal in gpio matrix*/ @@ -300,12 +214,8 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf) esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_channel(channel)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1; LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1; @@ -315,12 +225,8 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel) esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_channel(channel)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.channel_group[speed_mode].channel[channel].conf0.idle_lv = idle_level & 0x1; LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 0; @@ -331,18 +237,11 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t fade_direction, uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_channel(channel)) { - return ESP_ERR_INVALID_ARG; - } - if(fade_direction > LEDC_DUTY_DIR_INCREASE) { - LEDC_ERROR("Duty direction err\n"); - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(fade_direction <= LEDC_DUTY_DIR_INCREASE, "ledc fade direction error", ESP_ERR_INVALID_ARG); if(step_num > LEDC_DUTY_NUM_HSCH0_V || duty_cyle_num > LEDC_DUTY_CYCLE_HSCH0_V || duty_scale > LEDC_DUTY_SCALE_HSCH0_V) { - LEDC_ERROR("step_num=%u duty_cyle_num=%u duty_scale=%u\n", step_num, duty_cyle_num, duty_scale); + ESP_LOGE(LEDC_TAG, "step_num=%u duty_cyle_num=%u duty_scale=%u", step_num, duty_cyle_num, duty_scale); return ESP_ERR_INVALID_ARG; } ledc_duty_config(speed_mode, @@ -359,12 +258,8 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } - if(!ledc_is_valid_channel(channel)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); + LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG); ledc_duty_config(speed_mode, channel, //uint32_t chan_num, 0, //uint32_t hpoint_val, @@ -379,18 +274,14 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel) { - if(!ledc_is_valid_mode(speed_mode)) { - return -1; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (-1)); uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4); return duty; } esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz) { - if(!ledc_is_valid_mode(speed_mode)) { - return ESP_ERR_INVALID_ARG; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); esp_err_t ret = ESP_OK; uint32_t div_num = 0; @@ -403,7 +294,7 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t div_num = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision; } if(div_num <= 256 || div_num > LEDC_DIV_NUM_HSTIMER0) { - LEDC_ERROR("div param err,div_param=%u\n", div_num); + ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", div_num); ret = ESP_FAIL; } LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num = div_num; @@ -413,9 +304,7 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num) { - if(!ledc_is_valid_mode(speed_mode)) { - return 0; - } + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (0)); portENTER_CRITICAL(&ledc_spinlock); uint32_t freq = 0; uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel; diff --git a/components/driver/uart.c b/components/driver/uart.c new file mode 100644 index 0000000000..d9e3fd64ca --- /dev/null +++ b/components/driver/uart.c @@ -0,0 +1,1008 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include "esp_types.h" +#include "esp_attr.h" +#include "esp_intr.h" +#include "esp_log.h" +#include "malloc.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/xtensa_api.h" +#include "freertos/task.h" +#include "freertos/ringbuf.h" +#include "soc/dport_reg.h" +#include "rom/ets_sys.h" +#include "soc/uart_struct.h" +#include "driver/uart.h" +#include "driver/gpio.h" +#include "soc/uart_struct.h" + +static const char* UART_TAG = "UART"; +#define UART_CHECK(a, str, ret) if (!(a)) { \ + ESP_LOGE(UART_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ + return (ret); \ + } +#define UART_EMPTY_THRESH_DEFAULT (10) +#define UART_FULL_THRESH_DEFAULT (120) +#define UART_TOUT_THRESH_DEFAULT (10) +#define UART_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux) +#define UART_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux) +#define UART_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux) +#define UART_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux) + +typedef struct { + uart_event_type_t type; /*!< UART TX data type */ + struct { + int brk_len; + size_t size; + uint8_t data[0]; + } tx_data; +} uart_tx_data_t; + +typedef struct { + uart_port_t uart_num; /*!< UART port number*/ + int queue_size; /*!< UART event queue size*/ + QueueHandle_t xQueueUart; /*!< UART queue handler*/ + int intr_num; /*!< UART interrupt number*/ + //rx parameters + SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/ + int rx_buf_size; /*!< RX ring buffer size */ + RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler*/ + bool rx_buffer_full_flg; /*!< RX ring buffer full flag. */ + int rx_cur_remain; /*!< Data number that waiting to be read out in ring buffer item*/ + uint8_t* rx_ptr; /*!< pointer to the current data in ring buffer*/ + uint8_t* rx_head_ptr; /*!< pointer to the head of RX item*/ + uint8_t rx_data_buf[UART_FIFO_LEN]; /*!< Data buffer to stash FIFO data*/ + uint8_t rx_stash_len; /*!< stashed data length.(When using flow control, after reading out FIFO data, if we fail to push to buffer, we can just stash them.) */ + //tx parameters + SemaphoreHandle_t tx_fifo_sem; /*!< UART TX FIFO semaphore*/ + SemaphoreHandle_t tx_mux; /*!< UART TX mutex*/ + SemaphoreHandle_t tx_done_sem; /*!< UART TX done semaphore*/ + SemaphoreHandle_t tx_brk_sem; /*!< UART TX send break done semaphore*/ + int tx_buf_size; /*!< TX ring buffer size */ + RingbufHandle_t tx_ring_buf; /*!< TX ring buffer handler*/ + bool tx_waiting_fifo; /*!< this flag indicates that some task is waiting for FIFO empty interrupt, used to send all data without any data buffer*/ + uint8_t* tx_ptr; /*!< TX data pointer to push to FIFO in TX buffer mode*/ + uart_tx_data_t* tx_head; /*!< TX data pointer to head of the current buffer in TX ring buffer*/ + uint32_t tx_len_tot; /*!< Total length of current item in ring buffer*/ + uint32_t tx_len_cur; + uint8_t tx_brk_flg; /*!< Flag to indicate to send a break signal in the end of the item sending procedure */ + uint8_t tx_brk_len; /*!< TX break signal cycle length/number */ + uint8_t tx_waiting_brk; /*!< Flag to indicate that TX FIFO is ready to send break signal after FIFO is empty, do not push data into TX FIFO right now.*/ +} uart_obj_t; + + + +static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; +static uart_dev_t* UART[UART_NUM_MAX] = {&UART0, &UART1, &UART2}; +static portMUX_TYPE uart_spinlock[UART_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; + +esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((data_bit < UART_DATA_BITS_MAX), "data bit error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->conf0.bit_num = data_bit; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + *(data_bit) = UART[uart_num]->conf0.bit_num; + return ESP_OK; +} + +esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bit) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((stop_bit < UART_STOP_BITS_MAX), "stop bit error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->conf0.stop_bit_num = stop_bit; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + (*stop_bit) = UART[uart_num]->conf0.stop_bit_num; + return ESP_OK; +} + +esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->conf0.parity = parity_mode & 0x1; + UART[uart_num]->conf0.parity_en = (parity_mode >> 1) & 0x1; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + int val = UART[uart_num]->conf0.val; + if(val & UART_PARITY_EN_M) { + if(val & UART_PARITY_M) { + (*parity_mode) = UART_PARITY_ODD; + } else { + (*parity_mode) = UART_PARITY_EVEN; + } + } else { + (*parity_mode) = UART_PARITY_DISABLE; + } + return ESP_OK; +} + +esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((baud_rate < UART_BITRATE_MAX), "baud_rate error", ESP_FAIL); + uint32_t clk_div = (((UART_CLK_FREQ) << 4) / baud_rate); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->clk_div.div_int = clk_div >> 4; + UART[uart_num]->clk_div.div_frag = clk_div & 0xf; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + uint32_t clk_div = (UART[uart_num]->clk_div.div_int << 4) | UART[uart_num]->clk_div.div_frag; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + (*baudrate) = ((UART_CLK_FREQ) << 4) / clk_div; + return ESP_OK; +} + +esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((((inverse_mask & UART_LINE_INV_MASK) == 0) && (inverse_mask != 0)), "inverse_mask error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + CLEAR_PERI_REG_MASK(UART_CONF0_REG(uart_num), UART_LINE_INV_MASK); + SET_PERI_REG_MASK(UART_CONF0_REG(uart_num), inverse_mask); + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +//only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set. +esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((rx_thresh < UART_FIFO_LEN), "rx flow thresh error", ESP_FAIL); + UART_CHECK((flow_ctrl < UART_HW_FLOWCTRL_MAX), "hw_flowctrl mode error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + if(flow_ctrl & UART_HW_FLOWCTRL_RTS) { + UART[uart_num]->conf1.rx_flow_thrhd = rx_thresh; + UART[uart_num]->conf1.rx_flow_en = 1; + } else { + UART[uart_num]->conf1.rx_flow_en = 0; + } + if(flow_ctrl & UART_HW_FLOWCTRL_CTS) { + UART[uart_num]->conf0.tx_flow_en = 1; + } else { + UART[uart_num]->conf0.tx_flow_en = 0; + } + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + uart_hw_flowcontrol_t val = UART_HW_FLOWCTRL_DISABLE; + if(UART[uart_num]->conf1.rx_flow_en) { + val |= UART_HW_FLOWCTRL_RTS; + } + if(UART[uart_num]->conf0.tx_flow_en) { + val |= UART_HW_FLOWCTRL_CTS; + } + (*flow_ctrl) = val; + return ESP_OK; +} + +static esp_err_t uart_reset_fifo(uart_port_t uart_num) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->conf0.rxfifo_rst = 1; + UART[uart_num]->conf0.rxfifo_rst = 0; + UART[uart_num]->conf0.txfifo_rst = 1; + UART[uart_num]->conf0.txfifo_rst = 0; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + //intr_clr register is write-only + UART[uart_num]->int_clr.val = clr_mask; + return ESP_OK; +} + +esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask); + SET_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), enable_mask); + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask); + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_enable_rx_intr(uart_port_t uart_num) +{ + uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA); + return ESP_OK; +} + +esp_err_t uart_disable_rx_intr(uart_port_t uart_num) +{ + uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA); + return ESP_OK; +} + +esp_err_t uart_disable_tx_intr(uart_port_t uart_num) +{ + uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA); + return ESP_OK; +} + +esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((thresh < UART_FIFO_LEN), "empty intr threshold error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->int_clr.txfifo_empty = 1; + UART[uart_num]->conf1.txfifo_empty_thrhd = thresh & UART_TXFIFO_EMPTY_THRHD_V; + UART[uart_num]->int_ena.txfifo_empty = enable & 0x1; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + ESP_INTR_ENABLE(p_uart_obj[uart_num]->intr_num); + return ESP_OK; +} + +esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + ESP_INTR_DISABLE(uart_intr_num); + switch(uart_num) { + case UART_NUM_1: + intr_matrix_set(xPortGetCoreID(), ETS_UART1_INTR_SOURCE, uart_intr_num); + break; + case UART_NUM_2: + intr_matrix_set(xPortGetCoreID(), ETS_UART2_INTR_SOURCE, uart_intr_num); + break; + case UART_NUM_0: + default: + intr_matrix_set(xPortGetCoreID(), ETS_UART0_INTR_SOURCE, uart_intr_num); + break; + } + xt_set_interrupt_handler(uart_intr_num, fn, arg); + ESP_INTR_ENABLE(uart_intr_num); + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +//internal signal can be output to multiple GPIO pads +//only one GPIO pad can connect with input signal +esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((tx_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(tx_io_num))), "tx_io_num error", ESP_FAIL); + UART_CHECK((rx_io_num < 0 || (GPIO_IS_VALID_GPIO(rx_io_num))), "rx_io_num error", ESP_FAIL); + UART_CHECK((rts_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(rts_io_num))), "rts_io_num error", ESP_FAIL); + UART_CHECK((cts_io_num < 0 || (GPIO_IS_VALID_GPIO(cts_io_num))), "cts_io_num error", ESP_FAIL); + + int tx_sig, rx_sig, rts_sig, cts_sig; + switch(uart_num) { + case UART_NUM_0: + tx_sig = U0TXD_OUT_IDX; + rx_sig = U0RXD_IN_IDX; + rts_sig = U0RTS_OUT_IDX; + cts_sig = U0CTS_IN_IDX; + break; + case UART_NUM_1: + tx_sig = U1TXD_OUT_IDX; + rx_sig = U1RXD_IN_IDX; + rts_sig = U1RTS_OUT_IDX; + cts_sig = U1CTS_IN_IDX; + break; + case UART_NUM_2: + tx_sig = U2TXD_OUT_IDX; + rx_sig = U2RXD_IN_IDX; + rts_sig = U2RTS_OUT_IDX; + cts_sig = U2CTS_IN_IDX; + break; + case UART_NUM_MAX: + default: + tx_sig = U0TXD_OUT_IDX; + rx_sig = U0RXD_IN_IDX; + rts_sig = U0RTS_OUT_IDX; + cts_sig = U0CTS_IN_IDX; + break; + } + if(tx_io_num >= 0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO); + gpio_set_direction(tx_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(tx_io_num, tx_sig, 0, 0); + } + + if(rx_io_num >= 0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO); + gpio_set_direction(rx_io_num, GPIO_MODE_INPUT); + gpio_matrix_in(rx_io_num, rx_sig, 0); + } + if(rts_io_num >= 0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rts_io_num], PIN_FUNC_GPIO); + gpio_set_direction(rts_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(rts_io_num, rts_sig, 0, 0); + } + if(cts_io_num >= 0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cts_io_num], PIN_FUNC_GPIO); + gpio_set_direction(cts_io_num, GPIO_MODE_INPUT); + gpio_matrix_in(cts_io_num, cts_sig, 0); + } + return ESP_OK; +} + +esp_err_t uart_set_rts(uart_port_t uart_num, int level) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((UART[uart_num]->conf1.rx_flow_en != 1), "disable hw flowctrl before using sw control", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->conf0.sw_rts = level & 0x1; + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_set_dtr(uart_port_t uart_num, int level) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->conf0.sw_dtr = level & 0x1; + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((uart_config), "param null", ESP_FAIL); + if(uart_num == UART_NUM_0) { + periph_module_enable(PERIPH_UART0_MODULE); + } else if(uart_num == UART_NUM_1) { + periph_module_enable(PERIPH_UART1_MODULE); + } else if(uart_num == UART_NUM_2) { + periph_module_enable(PERIPH_UART2_MODULE); + } + uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh); + uart_set_baudrate(uart_num, uart_config->baud_rate); + UART[uart_num]->conf0.val = ( + (uart_config->parity << UART_PARITY_S) + | (uart_config->stop_bits << UART_STOP_BIT_NUM_S) + | (uart_config->data_bits << UART_BIT_NUM_S) + | ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0) + | UART_TICK_REF_ALWAYS_ON_M); + return ESP_OK; +} + +esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((intr_conf), "param null", ESP_FAIL); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->int_clr.val = UART_INTR_MASK; + if(intr_conf->intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M) { + UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V); + UART[uart_num]->conf1.rx_tout_en = 1; + } else { + UART[uart_num]->conf1.rx_tout_en = 0; + } + if(intr_conf->intr_enable_mask & UART_RXFIFO_FULL_INT_ENA_M) { + UART[uart_num]->conf1.rxfifo_full_thrhd = intr_conf->rxfifo_full_thresh; + } + if(intr_conf->intr_enable_mask & UART_TXFIFO_EMPTY_INT_ENA_M) { + UART[uart_num]->conf1.txfifo_empty_thrhd = intr_conf->txfifo_empty_intr_thresh; + } + UART[uart_num]->int_ena.val = intr_conf->intr_enable_mask; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_FAIL; +} + +//internal isr handler for default driver code. +static void IRAM_ATTR uart_rx_intr_handler_default(void *param) +{ + uart_obj_t *p_uart = (uart_obj_t*) param; + uint8_t uart_num = p_uart->uart_num; + uart_dev_t* uart_reg = UART[uart_num]; + uint8_t buf_idx = 0; + uint32_t uart_intr_status = UART[uart_num]->int_st.val; + int rx_fifo_len = 0; + uart_event_t uart_event; + portBASE_TYPE HPTaskAwoken = 0; + + while(uart_intr_status != 0x0) { + buf_idx = 0; + uart_event.type = UART_EVENT_MAX; + if(uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->int_ena.txfifo_empty = 0; + uart_reg->int_clr.txfifo_empty = 1; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + if(p_uart->tx_waiting_brk) { + return; + } + //TX semaphore will only be used when tx_buf_size is zero. + if(p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) { + p_uart->tx_waiting_fifo = false; + xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, NULL); + } + else { + //We don't use TX ring buffer, because the size if zero. + if(p_uart->tx_buf_size == 0) { + return; + } + int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt; + bool en_tx_flg = false; + //We need to put a loop here, in case all the buffer items are very short. + //That would cause a watch_dog reset because empty interrupt happens so often. + //Although this is a loop in ISR, this loop will execute at most 128 turns. + while(tx_fifo_rem) { + if(p_uart->tx_len_tot == 0 || p_uart->tx_ptr == NULL || p_uart->tx_len_cur == 0) { + size_t size; + p_uart->tx_head = (uart_tx_data_t*) xRingbufferReceiveFromISR(p_uart->tx_ring_buf, &size); + if(p_uart->tx_head) { + //The first item is the data description + //Get the first item to get the data information + if(p_uart->tx_len_tot == 0) { + p_uart->tx_ptr = NULL; + p_uart->tx_len_tot = p_uart->tx_head->tx_data.size; + if(p_uart->tx_head->type == UART_DATA_BREAK) { + p_uart->tx_len_tot = p_uart->tx_head->tx_data.size; + p_uart->tx_brk_flg = 1; + p_uart->tx_brk_len = p_uart->tx_head->tx_data.brk_len; + } + //We have saved the data description from the 1st item, return buffer. + vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); + }else if(p_uart->tx_ptr == NULL) { + //Update the TX item pointer, we will need this to return item to buffer. + p_uart->tx_ptr = (uint8_t*) p_uart->tx_head; + en_tx_flg = true; + p_uart->tx_len_cur = size; + } + } + else { + //Can not get data from ring buffer, return; + return; + } + } + if(p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) { + //To fill the TX FIFO. + int send_len = p_uart->tx_len_cur > tx_fifo_rem ? tx_fifo_rem : p_uart->tx_len_cur; + for(buf_idx = 0; buf_idx < send_len; buf_idx++) { + WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), *(p_uart->tx_ptr++) & 0xff); + } + p_uart->tx_len_tot -= send_len; + p_uart->tx_len_cur -= send_len; + tx_fifo_rem -= send_len; + if(p_uart->tx_len_cur == 0) { + //Return item to ring buffer. + vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); + p_uart->tx_head = NULL; + p_uart->tx_ptr = NULL; + //Sending item done, now we need to send break if there is a record. + //Set TX break signal after FIFO is empty + if(p_uart->tx_brk_flg == 1 && p_uart->tx_len_tot == 0) { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->int_ena.tx_brk_done = 0; + uart_reg->idle_conf.tx_brk_num = p_uart->tx_brk_len; + uart_reg->conf0.txd_brk = 1; + uart_reg->int_clr.tx_brk_done = 1; + uart_reg->int_ena.tx_brk_done = 1; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + p_uart->tx_waiting_brk = 1; + return; + } else { + //enable TX empty interrupt + en_tx_flg = true; + } + } else { + //enable TX empty interrupt + en_tx_flg = true; + } + } + } + if(en_tx_flg) { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->int_clr.txfifo_empty = 1; + uart_reg->int_ena.txfifo_empty = 1; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + } + } + } + else if((uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M) || (uart_intr_status & UART_RXFIFO_FULL_INT_ST_M)) { + if(p_uart->rx_buffer_full_flg == false) { + //Get the buffer from the FIFO + rx_fifo_len = uart_reg->status.rxfifo_cnt; + p_uart->rx_stash_len = rx_fifo_len; + //We have to read out all data in RX FIFO to clear the interrupt signal + while(buf_idx < rx_fifo_len) { + p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte; + } + //After Copying the Data From FIFO ,Clear intr_status + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->int_clr.rxfifo_tout = 1; + uart_reg->int_clr.rxfifo_full = 1; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_event.type = UART_DATA; + uart_event.size = rx_fifo_len; + //If we fail to push data to ring buffer, we will have to stash the data, and send next time. + //Mainly for applications that uses flow control or small ring buffer. + if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->int_ena.rxfifo_full = 0; + uart_reg->int_ena.rxfifo_tout = 0; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + p_uart->rx_buffer_full_flg = true; + uart_event.type = UART_BUFFER_FULL; + } else { + uart_event.type = UART_DATA; + } + } else { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->int_ena.rxfifo_full = 0; + uart_reg->int_ena.rxfifo_tout = 0; + uart_reg->int_clr.val = UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_event.type = UART_BUFFER_FULL; + } + } else if(uart_intr_status & UART_RXFIFO_OVF_INT_ST_M) { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->conf0.rxfifo_rst = 1; + uart_reg->conf0.rxfifo_rst = 0; + uart_reg->int_clr.rxfifo_ovf = 1; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_event.type = UART_FIFO_OVF; + } else if(uart_intr_status & UART_BRK_DET_INT_ST_M) { + uart_reg->int_clr.brk_det = 1; + uart_event.type = UART_BREAK; + } else if(uart_intr_status & UART_FRM_ERR_INT_ST_M) { + uart_reg->int_clr.parity_err = 1; + uart_event.type = UART_FRAME_ERR; + } else if(uart_intr_status & UART_PARITY_ERR_INT_ST_M) { + uart_reg->int_clr.frm_err = 1; + uart_event.type = UART_PARITY_ERR; + } else if(uart_intr_status & UART_TX_BRK_DONE_INT_ST_M) { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->conf0.txd_brk = 0; + uart_reg->int_ena.tx_brk_done = 0; + uart_reg->int_clr.tx_brk_done = 1; + if(p_uart->tx_brk_flg == 1) { + uart_reg->int_ena.txfifo_empty = 1; + } + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + if(p_uart->tx_brk_flg == 1) { + p_uart->tx_brk_flg = 0; + p_uart->tx_waiting_brk = 0; + } else { + xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken); + } + } else if(uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->int_ena.tx_brk_idle_done = 0; + uart_reg->int_clr.tx_brk_idle_done = 1; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + } else if(uart_intr_status & UART_TX_DONE_INT_ST_M) { + UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); + uart_reg->int_ena.tx_done = 0; + uart_reg->int_clr.tx_done = 1; + UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); + } + else { + uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/ + uart_event.type = UART_EVENT_MAX; + } + + if(uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) { + xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken); + } + uart_intr_status = uart_reg->int_st.val; + } +} + +/**************************************************************/ +esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); + BaseType_t res; + portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait; + //Take tx_mux + res = xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)ticks_to_wait); + if(res == pdFALSE) { + return ESP_ERR_TIMEOUT; + } + ticks_to_wait = ticks_end - xTaskGetTickCount(); + xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, 0); + ticks_to_wait = ticks_end - xTaskGetTickCount(); + if(UART[uart_num]->status.txfifo_cnt == 0) { + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return ESP_OK; + } + uart_enable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M); + //take 2nd tx_done_sem, wait given from ISR + res = xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, (portTickType)ticks_to_wait); + if(res == pdFALSE) { + uart_disable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M); + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return ESP_ERR_TIMEOUT; + } + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return ESP_OK; +} + +static esp_err_t uart_set_break(uart_port_t uart_num, int break_num) +{ + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->idle_conf.tx_brk_num = break_num; + UART[uart_num]->conf0.txd_brk = 1; + UART[uart_num]->int_clr.tx_brk_done = 1; + UART[uart_num]->int_ena.tx_brk_done = 1; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + return ESP_OK; +} + +//Fill UART tx_fifo and return a number, +//This function by itself is not thread-safe, always call from within a muxed section. +static int uart_fill_fifo(uart_port_t uart_num, const char* buffer, uint32_t len) +{ + uint8_t i = 0; + uint8_t tx_fifo_cnt = UART[uart_num]->status.txfifo_cnt; + uint8_t tx_remain_fifo_cnt = (UART_FIFO_LEN - tx_fifo_cnt); + uint8_t copy_cnt = (len >= tx_remain_fifo_cnt ? tx_remain_fifo_cnt : len); + for(i = 0; i < copy_cnt; i++) { + WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), buffer[i]); + } + return copy_cnt; +} + +int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); + UART_CHECK(buffer, "buffer null", (-1)); + if(len == 0) { + return 0; + } + xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY); + int tx_len = uart_fill_fifo(uart_num, (const char*) buffer, len); + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return tx_len; +} + +static int uart_tx_all(uart_port_t uart_num, const char* src, size_t size, bool brk_en, int brk_len) +{ + if(size == 0) { + return 0; + } + size_t original_size = size; + + //lock for uart_tx + xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY); + if(p_uart_obj[uart_num]->tx_buf_size > 0) { + int max_size = xRingbufferGetMaxItemSize(p_uart_obj[uart_num]->tx_ring_buf); + int offset = 0; + uart_tx_data_t evt; + evt.tx_data.size = size; + evt.tx_data.brk_len = brk_len; + if(brk_en) { + evt.type = UART_DATA_BREAK; + } else { + evt.type = UART_DATA; + } + xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) &evt, sizeof(uart_tx_data_t), portMAX_DELAY); + while(size > 0) { + int send_size = size > max_size / 2 ? max_size / 2 : size; + xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) (src + offset), send_size, portMAX_DELAY); + size -= send_size; + offset += send_size; + } + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT); + } else { + while(size) { + //semaphore for tx_fifo available + if(pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) { + size_t sent = uart_fill_fifo(uart_num, (char*) src, size); + if(sent < size) { + p_uart_obj[uart_num]->tx_waiting_fifo = true; + uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT); + } + size -= sent; + src += sent; + } + } + if(brk_en) { + uart_set_break(uart_num, brk_len); + xSemaphoreTake(p_uart_obj[uart_num]->tx_brk_sem, (portTickType)portMAX_DELAY); + } + xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem); + } + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return original_size; +} + +int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); + UART_CHECK((p_uart_obj[uart_num] != NULL), "uart driver error", (-1)); + UART_CHECK(src, "buffer null", (-1)); + return uart_tx_all(uart_num, src, size, 0, 0); +} + +int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); + UART_CHECK((size > 0), "uart size error", (-1)); + UART_CHECK((src), "uart data null", (-1)); + UART_CHECK((brk_len > 0 && brk_len < 256), "break_num error", (-1)); + return uart_tx_all(uart_num, src, size, 1, brk_len); +} + +int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); + UART_CHECK((buf), "uart_num error", (-1)); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); + uint8_t* data = NULL; + size_t size; + size_t copy_len = 0; + int len_tmp; + if(xSemaphoreTake(p_uart_obj[uart_num]->rx_mux,(portTickType)ticks_to_wait) != pdTRUE) { + return -1; + } + while(length) { + if(p_uart_obj[uart_num]->rx_cur_remain == 0) { + data = (uint8_t*) xRingbufferReceive(p_uart_obj[uart_num]->rx_ring_buf, &size, (portTickType) ticks_to_wait); + if(data) { + p_uart_obj[uart_num]->rx_head_ptr = data; + p_uart_obj[uart_num]->rx_ptr = data; + p_uart_obj[uart_num]->rx_cur_remain = size; + } else { + xSemaphoreGive(p_uart_obj[uart_num]->rx_mux); + return copy_len; + } + } + if(p_uart_obj[uart_num]->rx_cur_remain > length) { + len_tmp = length; + } else { + len_tmp = p_uart_obj[uart_num]->rx_cur_remain; + } + memcpy(buf + copy_len, p_uart_obj[uart_num]->rx_ptr, len_tmp); + p_uart_obj[uart_num]->rx_ptr += len_tmp; + p_uart_obj[uart_num]->rx_cur_remain -= len_tmp; + copy_len += len_tmp; + length -= len_tmp; + if(p_uart_obj[uart_num]->rx_cur_remain == 0) { + vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_head_ptr); + p_uart_obj[uart_num]->rx_head_ptr = NULL; + p_uart_obj[uart_num]->rx_ptr = NULL; + if(p_uart_obj[uart_num]->rx_buffer_full_flg) { + BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1); + if(res == pdTRUE) { + p_uart_obj[uart_num]->rx_buffer_full_flg = false; + uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num); + } + } + } + } + xSemaphoreGive(p_uart_obj[uart_num]->rx_mux); + return copy_len; +} + +esp_err_t uart_flush(uart_port_t uart_num) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); + uart_obj_t* p_uart = p_uart_obj[uart_num]; + uint8_t* data; + size_t size; + + //rx sem protect the ring buffer read related functions + xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY); + ESP_INTR_DISABLE(p_uart->intr_num); + while(true) { + if(p_uart->rx_head_ptr) { + vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr); + p_uart->rx_ptr = NULL; + p_uart->rx_cur_remain = 0; + p_uart->rx_head_ptr = NULL; + } + data = (uint8_t*) xRingbufferReceive(p_uart->rx_ring_buf, &size, (portTickType) 0); + if(data == NULL) { + break; + } + vRingbufferReturnItem(p_uart->rx_ring_buf, data); + } + p_uart->rx_ptr = NULL; + p_uart->rx_cur_remain = 0; + p_uart->rx_head_ptr = NULL; + ESP_INTR_ENABLE(p_uart->intr_num); + xSemaphoreGive(p_uart->rx_mux); + + if(p_uart->tx_buf_size > 0) { + xSemaphoreTake(p_uart->tx_mux, (portTickType)portMAX_DELAY); + ESP_INTR_DISABLE(p_uart->intr_num); + UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART[uart_num]->int_ena.txfifo_empty = 0; + UART[uart_num]->int_clr.txfifo_empty = 1; + UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + do { + data = (uint8_t*) xRingbufferReceive(p_uart->tx_ring_buf, &size, (portTickType) 0); + if(data == NULL) { + break; + } + vRingbufferReturnItem(p_uart->rx_ring_buf, data); + } while(1); + p_uart->tx_brk_flg = 0; + p_uart->tx_brk_len = 0; + p_uart->tx_head = NULL; + p_uart->tx_len_cur = 0; + p_uart->tx_len_tot = 0; + p_uart->tx_ptr = NULL; + p_uart->tx_waiting_brk = 0; + p_uart->tx_waiting_fifo = false; + ESP_INTR_ENABLE(p_uart->intr_num); + xSemaphoreGive(p_uart->tx_mux); + } + uart_reset_fifo(uart_num); + return ESP_OK; +} + +esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, int uart_intr_num, void* uart_queue) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + UART_CHECK((rx_buffer_size > 0), "uart rx buffer length error", ESP_FAIL); + if(p_uart_obj[uart_num] == NULL) { + ESP_INTR_DISABLE(uart_intr_num); + p_uart_obj[uart_num] = (uart_obj_t*) malloc(sizeof(uart_obj_t)); + if(p_uart_obj[uart_num] == NULL) { + ESP_LOGE(UART_TAG, "UART driver malloc error"); + return ESP_FAIL; + } + p_uart_obj[uart_num]->uart_num = uart_num; + p_uart_obj[uart_num]->tx_fifo_sem = xSemaphoreCreateBinary(); + xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem); + p_uart_obj[uart_num]->tx_done_sem = xSemaphoreCreateBinary(); + p_uart_obj[uart_num]->tx_brk_sem = xSemaphoreCreateBinary(); + p_uart_obj[uart_num]->tx_mux = xSemaphoreCreateMutex(); + p_uart_obj[uart_num]->rx_mux = xSemaphoreCreateMutex(); + p_uart_obj[uart_num]->intr_num = uart_intr_num; + p_uart_obj[uart_num]->queue_size = queue_size; + p_uart_obj[uart_num]->tx_ptr = NULL; + p_uart_obj[uart_num]->tx_head = NULL; + p_uart_obj[uart_num]->tx_len_tot = 0; + p_uart_obj[uart_num]->tx_brk_flg = 0; + p_uart_obj[uart_num]->tx_brk_len = 0; + p_uart_obj[uart_num]->tx_waiting_brk = 0; + + if(uart_queue) { + p_uart_obj[uart_num]->xQueueUart = xQueueCreate(queue_size, sizeof(uart_event_t)); + *((QueueHandle_t*) uart_queue) = p_uart_obj[uart_num]->xQueueUart; + ESP_LOGI(UART_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_uart_obj[uart_num]->xQueueUart)); + } else { + p_uart_obj[uart_num]->xQueueUart = NULL; + } + p_uart_obj[uart_num]->rx_buffer_full_flg = false; + p_uart_obj[uart_num]->tx_waiting_fifo = false; + p_uart_obj[uart_num]->rx_ptr = NULL; + p_uart_obj[uart_num]->rx_cur_remain = 0; + p_uart_obj[uart_num]->rx_head_ptr = NULL; + p_uart_obj[uart_num]->rx_ring_buf = xRingbufferCreate(rx_buffer_size, RINGBUF_TYPE_BYTEBUF); + if(tx_buffer_size > 0) { + p_uart_obj[uart_num]->tx_ring_buf = xRingbufferCreate(tx_buffer_size, RINGBUF_TYPE_NOSPLIT); + p_uart_obj[uart_num]->tx_buf_size = tx_buffer_size; + } else { + p_uart_obj[uart_num]->tx_ring_buf = NULL; + p_uart_obj[uart_num]->tx_buf_size = 0; + } + } else { + ESP_LOGE(UART_TAG, "UART driver already installed"); + return ESP_FAIL; + } + uart_isr_register(uart_num, uart_intr_num, uart_rx_intr_handler_default, p_uart_obj[uart_num]); + uart_intr_config_t uart_intr = { + .intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M + | UART_RXFIFO_TOUT_INT_ENA_M + | UART_FRM_ERR_INT_ENA_M + | UART_RXFIFO_OVF_INT_ENA_M + | UART_BRK_DET_INT_ENA_M, + .rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT, + .rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT, + .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT + }; + uart_intr_config(uart_num, &uart_intr); + ESP_INTR_ENABLE(uart_intr_num); + return ESP_OK; +} + +//Make sure no other tasks are still using UART before you call this function +esp_err_t uart_driver_delete(uart_port_t uart_num) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); + if(p_uart_obj[uart_num] == NULL) { + ESP_LOGI(UART_TAG, "ALREADY NULL"); + return ESP_OK; + } + ESP_INTR_DISABLE(p_uart_obj[uart_num]->intr_num); + uart_disable_rx_intr(uart_num); + uart_disable_tx_intr(uart_num); + uart_isr_register(uart_num, p_uart_obj[uart_num]->intr_num, NULL, NULL); + + if(p_uart_obj[uart_num]->tx_fifo_sem) { + vSemaphoreDelete(p_uart_obj[uart_num]->tx_fifo_sem); + p_uart_obj[uart_num]->tx_fifo_sem = NULL; + } + if(p_uart_obj[uart_num]->tx_done_sem) { + vSemaphoreDelete(p_uart_obj[uart_num]->tx_done_sem); + p_uart_obj[uart_num]->tx_done_sem = NULL; + } + if(p_uart_obj[uart_num]->tx_brk_sem) { + vSemaphoreDelete(p_uart_obj[uart_num]->tx_brk_sem); + p_uart_obj[uart_num]->tx_brk_sem = NULL; + } + if(p_uart_obj[uart_num]->tx_mux) { + vSemaphoreDelete(p_uart_obj[uart_num]->tx_mux); + p_uart_obj[uart_num]->tx_mux = NULL; + } + if(p_uart_obj[uart_num]->rx_mux) { + vSemaphoreDelete(p_uart_obj[uart_num]->rx_mux); + p_uart_obj[uart_num]->rx_mux = NULL; + } + if(p_uart_obj[uart_num]->xQueueUart) { + vQueueDelete(p_uart_obj[uart_num]->xQueueUart); + p_uart_obj[uart_num]->xQueueUart = NULL; + } + if(p_uart_obj[uart_num]->rx_ring_buf) { + vRingbufferDelete(p_uart_obj[uart_num]->rx_ring_buf); + p_uart_obj[uart_num]->rx_ring_buf = NULL; + } + if(p_uart_obj[uart_num]->tx_ring_buf) { + vRingbufferDelete(p_uart_obj[uart_num]->tx_ring_buf); + p_uart_obj[uart_num]->tx_ring_buf = NULL; + } + + free(p_uart_obj[uart_num]); + p_uart_obj[uart_num] = NULL; + return ESP_OK; +} diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 535df23eb5..1f04cf4bb7 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -63,14 +63,28 @@ config MEMMAP_TRACEMEM of memory that can't be used for general purposes anymore. Disable this if you do not know what this is. +config MEMMAP_TRACEMEM_TWOBANKS + bool "Reserve memory for tracing both pro as well as app cpu execution" + default "n" + depends on MEMMAP_TRACEMEM && MEMMAP_SMP + help + The ESP32 contains a feature which allows you to trace the execution path the processor + has taken through the program. This is stored in a chunk of 32K (16K for single-processor) + of memory that can't be used for general purposes anymore. Disable this if you do not know + what this is. + + # Memory to reverse for trace, used in linker script config TRACEMEM_RESERVE_DRAM hex - default 0x8000 if MEMMAP_TRACEMEM + default 0x8000 if MEMMAP_TRACEMEM && MEMMAP_TRACEMEM_TWOBANKS + default 0x4000 if MEMMAP_TRACEMEM && !MEMMAP_TRACEMEM_TWOBANKS default 0x0 +# Not implemented and/or needs new silicon rev to work config MEMMAP_SPISRAM bool "Use external SPI SRAM chip as main memory" + depends on ESP32_NEEDS_NEW_SILICON_REV default "n" help The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the @@ -140,4 +154,214 @@ config ULP_COPROC_RESERVE_MEM default 0 depends on !ULP_COPROC_ENABLED + +choice ESP32_PANIC + prompt "Panic handler behaviour" + default ESP32_PANIC_PRINT_REBOOT + help + If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is + invoked. Configure the panic handlers action here. + +config ESP32_PANIC_PRINT_HALT + bool "Print registers and halt" + help + Outputs the relevant registers over the serial port and halt the + processor. Needs a manual reset to restart. + +config ESP32_PANIC_PRINT_REBOOT + bool "Print registers and reboot" + help + Outputs the relevant registers over the serial port and immediately + reset the processor. + +config ESP32_PANIC_SILENT_REBOOT + bool "Silent reboot" + help + Just resets the processor without outputting anything + +config ESP32_PANIC_GDBSTUB + bool "Invoke GDBStub" + help + Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem + of the crash. +endchoice + +config ESP32_DEBUG_OCDAWARE + bool "Make exception and panic handlers JTAG/OCD aware" + default y + help + The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and + instead of panicking, have the debugger stop on the offending instruction. + + +config INT_WDT + bool "Interrupt watchdog" + default y + help + This watchdog timer can detect if the FreeRTOS tick interrupt has not been called for a certain time, + either because a task turned off interrupts and did not turn them on for a long time, or because an + interrupt handler did not return. It will try to invoke the panic handler first and failing that + reset the SoC. + +config INT_WDT_TIMEOUT_MS + int "Interrupt watchdog timeout (ms)" + depends on INT_WDT + default 300 + range 10 10000 + help + The timeout of the watchdog, in miliseconds. Make this higher than the FreeRTOS tick rate. + +config INT_WDT_CHECK_CPU1 + bool "Also watch CPU1 tick interrupt" + depends on INT_WDT && !FREERTOS_UNICORE + default y + help + Also detect if interrupts on CPU 1 are disabled for too long. + +config TASK_WDT + bool "Task watchdog" + default y + help + This watchdog timer can be used to make sure individual tasks are still running. + +config TASK_WDT_PANIC + bool "Invoke panic handler when Task Watchdog is triggered" + depends on TASK_WDT + default n + help + Normally, the Task Watchdog will only print out a warning if it detects it has not + been fed. If this is enabled, it will invoke the panic handler instead, which + can then halt or reboot the chip. + +config TASK_WDT_TIMEOUT_S + int "Task watchdog timeout (seconds)" + depends on TASK_WDT + range 1 60 + default 5 + help + Timeout for the task WDT, in seconds. + +config TASK_WDT_CHECK_IDLE_TASK + bool "Task watchdog watches CPU0 idle task" + depends on TASK_WDT + default y + help + With this turned on, the task WDT can detect if the idle task is not called within the task + watchdog timeout period. The idle task not being called usually is a symptom of another + task hoarding the CPU. It is also a bad thing because FreeRTOS household tasks depend on the + idle task getting some runtime every now and then. Take Care: With this disabled, this + watchdog will trigger if no tasks register themselves within the timeout value. + +config TASK_WDT_CHECK_IDLE_TASK_CPU1 + bool "Task watchdog also watches CPU1 idle task" + depends on TASK_WDT_CHECK_IDLE_TASK && !FREERTOS_UNICORE + default y + help + Also check the idle task that runs on CPU1. + +#The brownout detector code is disabled (by making it depend on a nonexisting symbol) because the current revision of ESP32 +#silicon has a bug in the brown-out detector, rendering it unusable for resetting the CPU. +config BROWNOUT_DET + bool "Hardware brownout detect & reset" + default y + depends on NEEDS_ESP32_NEW_SILICON_REV + help + The ESP32 has a built-in brownout detector which can detect if the voltage is lower than + a specific value. If this happens, it will reset the chip in order to prevent unintended + behaviour. + +choice BROWNOUT_DET_LVL_SEL + prompt "Brownout voltage level" + depends on BROWNOUT_DET + default BROWNOUT_DET_LVL_SEL_25 + help + The brownout detector will reset the chip when the supply voltage is below this level. + +#The voltage levels here are estimates, more work needs to be done to figure out the exact voltages +#of the brownout threshold levels. +config BROWNOUT_DET_LVL_SEL_0 + bool "2.1V" +config BROWNOUT_DET_LVL_SEL_1 + bool "2.2V" +config BROWNOUT_DET_LVL_SEL_2 + bool "2.3V" +config BROWNOUT_DET_LVL_SEL_3 + bool "2.4V" +config BROWNOUT_DET_LVL_SEL_4 + bool "2.5V" +config BROWNOUT_DET_LVL_SEL_5 + bool "2.6V" +config BROWNOUT_DET_LVL_SEL_6 + bool "2.7V" +config BROWNOUT_DET_LVL_SEL_7 + bool "2.8V" +endchoice + +config BROWNOUT_DET_LVL + int + default 0 if BROWNOUT_DET_LVL_SEL_0 + default 1 if BROWNOUT_DET_LVL_SEL_1 + default 2 if BROWNOUT_DET_LVL_SEL_2 + default 3 if BROWNOUT_DET_LVL_SEL_3 + default 4 if BROWNOUT_DET_LVL_SEL_4 + default 5 if BROWNOUT_DET_LVL_SEL_5 + default 6 if BROWNOUT_DET_LVL_SEL_6 + default 7 if BROWNOUT_DET_LVL_SEL_7 + + +config BROWNOUT_DET_RESETDELAY + int "Brownout reset delay (in uS)" + depends on BROWNOUT_DET + range 0 6820 + default 1000 + help + The brownout detector can reset the chip after a certain delay, in order to make sure e.g. a voltage dip has entirely passed + before trying to restart the chip. You can set the delay here. + + +choice ESP32_TIME_SYSCALL + prompt "Timers used for gettimeofday function" + default ESP32_TIME_SYSCALL_USE_RTC_FRC1 + help + This setting defines which hardware timers are used to + implement 'gettimeofday' and 'time' functions in C library. + + - If only FRC1 timer is used, gettimeofday will provide time at + microsecond resolution. Time will not be preserved when going + into deep sleep mode. + - If both FRC1 and RTC timers are used, timekeeping will + continue in deep sleep. Time will be reported at 1 microsecond + resolution. + - If only RTC timer is used, timekeeping will continue in + deep sleep, but time will be measured at 6.(6) microsecond + resolution. Also the gettimeofday function itself may take + longer to run. + - If no timers are used, gettimeofday and time functions + return -1 and set errno to ENOSYS. + +config ESP32_TIME_SYSCALL_USE_RTC + bool "RTC" +config ESP32_TIME_SYSCALL_USE_RTC_FRC1 + bool "RTC and FRC1" +config ESP32_TIME_SYSCALL_USE_FRC1 + bool "FRC1" +config ESP32_TIME_SYSCALL_USE_NONE + bool "None" +endchoice + +choice ESP32_RTC_CLOCK_SOURCE + prompt "RTC clock source" + default ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC + help + Choose which clock is used as RTC clock source. + The only available option for now is to use internal + 150kHz RC oscillator. + +config ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC + bool "Internal RC" +config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL + bool "External 32kHz crystal" + depends on DOCUMENTATION_FOR_RTC_CNTL +endchoice + endmenu diff --git a/components/esp32/brownout.c b/components/esp32/brownout.c new file mode 100644 index 0000000000..1dcde078e3 --- /dev/null +++ b/components/esp32/brownout.c @@ -0,0 +1,39 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include +#include "sdkconfig.h" +#include "soc/soc.h" +#include "soc/rtc_cntl_reg.h" + + +#if CONFIG_BROWNOUT_DET +/* +This file is included in esp-idf, but the menuconfig option for this is disabled because a silicon bug +prohibits the brownout detector from functioning correctly on the ESP32. +*/ + +void esp_brownout_init() { + WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, + RTC_CNTL_BROWN_OUT_ENA | (CONFIG_BROWNOUT_DET_LVL << RTC_CNTL_DBROWN_OUT_THRES_S) | + RTC_CNTL_BROWN_OUT_RST_ENA | (((CONFIG_BROWNOUT_DET_RESETDELAY*150)/1000) << RTC_CNTL_BROWN_OUT_RST_WAIT_S) | + RTC_CNTL_BROWN_OUT_PD_RF_ENA|RTC_CNTL_BROWN_OUT_CLOSE_FLASH_ENA); + +} + +#endif \ No newline at end of file diff --git a/components/esp32/component.mk b/components/esp32/component.mk index b41acee60d..040c686e5e 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -1,28 +1,20 @@ # # Component Makefile # -# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default, -# this will take the sources in this directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the esp-idf build system document if you need to do this. -# --include $(PROJECT_PATH)/build/include/config/auto.conf COMPONENT_SRCDIRS := . hwcrypto -LIBS := crypto core net80211 phy rtc pp wpa smartconfig +LIBS := core net80211 phy rtc pp wpa smartconfig coexist wps LINKER_SCRIPTS += -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld COMPONENT_ADD_LDFLAGS := -lesp32 \ - $(abspath libhal.a) \ - -L$(abspath lib) \ + $(COMPONENT_PATH)/libhal.a \ + -L$(COMPONENT_PATH)/lib \ $(addprefix -l,$(LIBS)) \ - -L $(abspath ld) \ + -L $(COMPONENT_PATH)/ld \ $(LINKER_SCRIPTS) -include $(IDF_PATH)/make/component_common.mk - ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) # automatically trigger a git submodule update diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 7b2ccdc609..a96fdee950 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -19,6 +19,8 @@ #include "rom/ets_sys.h" #include "rom/uart.h" +#include "rom/rtc.h" +#include "rom/cache.h" #include "soc/cpu.h" #include "soc/dport_reg.h" @@ -41,7 +43,14 @@ #include "esp_event.h" #include "esp_spi_flash.h" #include "esp_ipc.h" +#include "esp_crosscore_int.h" #include "esp_log.h" +#include "esp_vfs_dev.h" +#include "esp_newlib.h" +#include "esp_brownout.h" +#include "esp_int_wdt.h" +#include "esp_task_wdt.h" +#include "trax.h" void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))); void start_cpu0_default(void) IRAM_ATTR; @@ -54,11 +63,12 @@ static bool app_cpu_started = false; static void do_global_ctors(void); static void main_task(void* args); -extern void ets_setup_syscalls(void); extern void app_main(void); extern int _bss_start; extern int _bss_end; +extern int _rtc_bss_start; +extern int _rtc_bss_end; extern int _init_start; extern void (*__init_array_start)(void); extern void (*__init_array_end)(void); @@ -89,6 +99,11 @@ void IRAM_ATTR call_start_cpu0() memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); + /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ + if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) { + memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); + } + // Initialize heap allocator heap_alloc_caps_init(); @@ -96,7 +111,13 @@ void IRAM_ATTR call_start_cpu0() #if !CONFIG_FREERTOS_UNICORE ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); - + //Flush and enable icache for APP CPU + Cache_Flush(1); + Cache_Read_Enable(1); + //Un-stall the app cpu; the panic handler may have stalled it. + CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M); + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M); + //Enable clock gating and reset the app cpu. SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); @@ -131,12 +152,41 @@ void IRAM_ATTR call_start_cpu1() void start_cpu0_default(void) { +//Enable trace memory and immediately start trace. +#if CONFIG_MEMMAP_TRACEMEM +#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS + trax_enable(TRAX_ENA_PRO_APP); +#else + trax_enable(TRAX_ENA_PRO); +#endif + trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif esp_set_cpu_freq(); // set CPU frequency configured in menuconfig uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200); - ets_setup_syscalls(); +#if CONFIG_BROWNOUT_DET + esp_brownout_init(); +#endif +#if CONFIG_INT_WDT + esp_int_wdt_init(); +#endif +#if CONFIG_TASK_WDT + esp_task_wdt_init(); +#endif + esp_setup_syscall_table(); + esp_setup_time_syscalls(); + esp_vfs_dev_uart_register(); + esp_reent_init(_GLOBAL_REENT); + const char* default_uart_dev = "/dev/uart/0"; + _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r"); + _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w"); + _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w"); do_global_ctors(); +#if !CONFIG_FREERTOS_UNICORE + esp_crosscore_int_init(); +#endif esp_ipc_init(); spi_flash_init(); + xTaskCreatePinnedToCore(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL, 0); @@ -147,10 +197,14 @@ void start_cpu0_default(void) #if !CONFIG_FREERTOS_UNICORE void start_cpu1_default(void) { +#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS + trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif // Wait for FreeRTOS initialization to finish on PRO CPU while (port_xSchedulerRunning[0] == 0) { ; } + esp_crosscore_int_init(); ESP_LOGI(TAG, "Starting scheduler on APP CPU."); xPortStartScheduler(); } diff --git a/components/esp32/crosscore_int.c b/components/esp32/crosscore_int.c new file mode 100644 index 0000000000..60f972a2a2 --- /dev/null +++ b/components/esp32/crosscore_int.c @@ -0,0 +1,98 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include + +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_intr.h" + +#include "rom/ets_sys.h" +#include "rom/uart.h" + +#include "soc/cpu.h" +#include "soc/dport_reg.h" +#include "soc/io_mux_reg.h" +#include "soc/rtc_cntl_reg.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/portmacro.h" + + +#define REASON_YIELD (1<<0) + +static portMUX_TYPE reasonSpinlock = portMUX_INITIALIZER_UNLOCKED; +static volatile uint32_t reason[ portNUM_PROCESSORS ]; + + +/* +ToDo: There is a small chance the CPU already has yielded when this ISR is serviced. In that case, it's running the intended task but +the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably just schedule the task again, but have to check that. +*/ +static void esp_crosscore_isr(void *arg) { + uint32_t myReasonVal; + //A pointer to the correct reason array item is passed to this ISR. + volatile uint32_t *myReason=arg; + + //Clear the interrupt first. + if (xPortGetCoreID()==0) { + WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0); + } else { + WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, 0); + } + //Grab the reason and clear it. + portENTER_CRITICAL(&reasonSpinlock); + myReasonVal=*myReason; + *myReason=0; + portEXIT_CRITICAL(&reasonSpinlock); + + //Check what we need to do. + if (myReasonVal&REASON_YIELD) { + portYIELD_FROM_ISR(); + } +} + +//Initialize the crosscore interrupt on this core. Call this once +//on each active core. +void esp_crosscore_int_init() { + portENTER_CRITICAL(&reasonSpinlock); + reason[xPortGetCoreID()]=0; + portEXIT_CRITICAL(&reasonSpinlock); + ESP_INTR_DISABLE(ETS_FROM_CPU_INUM); + if (xPortGetCoreID()==0) { + intr_matrix_set(xPortGetCoreID(), ETS_FROM_CPU_INTR0_SOURCE, ETS_FROM_CPU_INUM); + } else { + intr_matrix_set(xPortGetCoreID(), ETS_FROM_CPU_INTR1_SOURCE, ETS_FROM_CPU_INUM); + } + xt_set_interrupt_handler(ETS_FROM_CPU_INUM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()]); + ESP_INTR_ENABLE(ETS_FROM_CPU_INUM); +} + +void esp_crosscore_int_send_yield(int coreId) { + assert(coreIdevent_info.got_ip.ip_info.ip), @@ -92,7 +97,7 @@ esp_err_t system_event_ap_start_handle_default(system_event_t *event) tcpip_adapter_ip_info_t ap_ip; uint8_t ap_mac[6]; - WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_AP, (wifi_rxcb_t)tcpip_adapter_ap_input), ESP_OK); + WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(WIFI_IF_AP, (wifi_rxcb_t)tcpip_adapter_ap_input), ESP_OK); WIFI_API_CALL_CHECK("esp_wifi_mac_get", esp_wifi_get_mac(WIFI_IF_AP, ap_mac), ESP_OK); tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ap_ip); @@ -103,7 +108,7 @@ esp_err_t system_event_ap_start_handle_default(system_event_t *event) esp_err_t system_event_ap_stop_handle_default(system_event_t *event) { - WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_AP, NULL), ESP_OK); + WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(WIFI_IF_AP, NULL), ESP_OK); tcpip_adapter_stop(TCPIP_ADAPTER_IF_AP); @@ -133,7 +138,7 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event) { tcpip_adapter_dhcp_status_t status; - WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_STA, (wifi_rxcb_t)tcpip_adapter_sta_input), ESP_OK); + WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(WIFI_IF_STA, (wifi_rxcb_t)tcpip_adapter_sta_input), ESP_OK); tcpip_adapter_up(TCPIP_ADAPTER_IF_STA); @@ -165,7 +170,7 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event) esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event) { tcpip_adapter_down(TCPIP_ADAPTER_IF_STA); - WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_STA, NULL), ESP_OK); + WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(WIFI_IF_STA, NULL), ESP_OK); return ESP_OK; } @@ -196,16 +201,14 @@ static esp_err_t esp_system_event_debug(system_event_t *event) } case SYSTEM_EVENT_STA_CONNECTED: { system_event_sta_connected_t *connected = &event->event_info.connected; - ESP_LOGD(TAG, "SYSTEM_EVENT_STA_CONNECTED, ssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d", \ - connected->ssid, connected->ssid_len, connected->bssid[0], connected->bssid[0], connected->bssid[1], \ - connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel, connected->authmode); + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_CONNECTED, ssid:%s, ssid_len:%d, bssid:" MACSTR ", channel:%d, authmode:%d", \ + connected->ssid, connected->ssid_len, MAC2STR(connected->bssid), connected->channel, connected->authmode); break; } case SYSTEM_EVENT_STA_DISCONNECTED: { system_event_sta_disconnected_t *disconnected = &event->event_info.disconnected; - ESP_LOGD(TAG, "SYSTEM_EVENT_STA_DISCONNECTED, ssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d", \ - disconnected->ssid, disconnected->ssid_len, disconnected->bssid[0], disconnected->bssid[0], disconnected->bssid[1], \ - disconnected->bssid[3], disconnected->bssid[4], disconnected->bssid[5], disconnected->reason); + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_DISCONNECTED, ssid:%s, ssid_len:%d, bssid:" MACSTR ", reason:%d", \ + disconnected->ssid, disconnected->ssid_len, MAC2STR(disconnected->bssid), disconnected->reason); break; } case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: { @@ -221,6 +224,22 @@ static esp_err_t esp_system_event_debug(system_event_t *event) IP2STR(&got_ip->ip_info.gw)); break; } + case SYSTEM_EVENT_STA_WPS_ER_SUCCESS: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_SUCCESS"); + break; + } + case SYSTEM_EVENT_STA_WPS_ER_FAILED: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_FAILED"); + break; + } + case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_TIMEOUT"); + break; + } + case SYSTEM_EVENT_STA_WPS_ER_PIN: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PIN"); + break; + } case SYSTEM_EVENT_AP_START: { ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START"); break; @@ -231,23 +250,21 @@ static esp_err_t esp_system_event_debug(system_event_t *event) } case SYSTEM_EVENT_AP_STACONNECTED: { system_event_ap_staconnected_t *staconnected = &event->event_info.sta_connected; - ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STACONNECTED, mac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d", \ - staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \ - staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid); + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STACONNECTED, mac:" MACSTR ", aid:%d", \ + MAC2STR(staconnected->mac), staconnected->aid); break; } case SYSTEM_EVENT_AP_STADISCONNECTED: { system_event_ap_stadisconnected_t *stadisconnected = &event->event_info.sta_disconnected; - ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED, mac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d", \ - stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \ - stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid); + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED, mac:" MACSTR ", aid:%d", \ + MAC2STR(stadisconnected->mac), stadisconnected->aid); break; } case SYSTEM_EVENT_AP_PROBEREQRECVED: { system_event_ap_probe_req_rx_t *ap_probereqrecved = &event->event_info.ap_probereqrecved; - ESP_LOGD(TAG, "SYSTEM_EVENT_AP_PROBEREQRECVED, rssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x", \ - ap_probereqrecved->rssi, ap_probereqrecved->mac[0], ap_probereqrecved->mac[0], ap_probereqrecved->mac[1], \ - ap_probereqrecved->mac[3], ap_probereqrecved->mac[4], ap_probereqrecved->mac[5]); + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_PROBEREQRECVED, rssi:%d, mac:" MACSTR, \ + ap_probereqrecved->rssi, \ + MAC2STR(ap_probereqrecved->mac)); break; } default: { diff --git a/components/esp32/freertos_hooks.c b/components/esp32/freertos_hooks.c new file mode 100644 index 0000000000..d59a20363d --- /dev/null +++ b/components/esp32/freertos_hooks.c @@ -0,0 +1,96 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include "esp_attr.h" +#include "esp_freertos_hooks.h" + +//We use just a static array here because it's not expected many components will need +//an idle or tick hook. +#define MAX_HOOKS 8 + +static esp_freertos_idle_cb_t idle_cb[MAX_HOOKS]={0}; +static esp_freertos_tick_cb_t tick_cb[MAX_HOOKS]={0}; + +void IRAM_ATTR esp_vApplicationTickHook() +{ + int n; + for (n=0; n -#include "heap_alloc_caps.h" +#include "esp_heap_alloc_caps.h" #include "spiram.h" #include "esp_log.h" @@ -40,23 +40,23 @@ Tag descriptors. These describe the capabilities of a bit of memory that's tagge Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request. */ static const uint32_t tagDesc[][NO_PRIOS]={ - { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, //Tag 0: Plain ole D-port RAM - { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, //Tag 1: Plain ole D-port RAM which has an alias on the I-port - { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }, //Tag 2: IRAM - { MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //Tag 3-8: PID 2-7 IRAM - { MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //Tag 9-14: PID 2-7 DRAM - { MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, //Tag 15: SPI SRAM data - { MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID } //End + { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, //Tag 0: Plain ole D-port RAM + { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, //Tag 1: Plain ole D-port RAM which has an alias on the I-port + { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }, //Tag 2: IRAM + { MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //Tag 3-8: PID 2-7 IRAM + { MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //Tag 9-14: PID 2-7 DRAM + { MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // + { MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // + { MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, //Tag 15: SPI SRAM data + { MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID } //End }; /* @@ -79,81 +79,81 @@ be sorted from low to high start address. This array is *NOT* const because it gets modified depending on what pools are/aren't available. */ static HeapRegionTagged_t regions[]={ - { (uint8_t *)0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available - { (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code - { (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- can be used for BT - { (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- can be used for BT - { (uint8_t *)0x3FFC0000, 0x2000, 0, 0}, //pool 10-13, mmu page 0 - { (uint8_t *)0x3FFC2000, 0x2000, 0, 0}, //pool 10-13, mmu page 1 - { (uint8_t *)0x3FFC4000, 0x2000, 0, 0}, //pool 10-13, mmu page 2 - { (uint8_t *)0x3FFC6000, 0x2000, 0, 0}, //pool 10-13, mmu page 3 - { (uint8_t *)0x3FFC8000, 0x2000, 0, 0}, //pool 10-13, mmu page 4 - { (uint8_t *)0x3FFCA000, 0x2000, 0, 0}, //pool 10-13, mmu page 5 - { (uint8_t *)0x3FFCC000, 0x2000, 0, 0}, //pool 10-13, mmu page 6 - { (uint8_t *)0x3FFCE000, 0x2000, 0, 0}, //pool 10-13, mmu page 7 - { (uint8_t *)0x3FFD0000, 0x2000, 0, 0}, //pool 10-13, mmu page 8 - { (uint8_t *)0x3FFD2000, 0x2000, 0, 0}, //pool 10-13, mmu page 9 - { (uint8_t *)0x3FFD4000, 0x2000, 0, 0}, //pool 10-13, mmu page 10 - { (uint8_t *)0x3FFD6000, 0x2000, 0, 0}, //pool 10-13, mmu page 11 - { (uint8_t *)0x3FFD8000, 0x2000, 0, 0}, //pool 10-13, mmu page 12 - { (uint8_t *)0x3FFDA000, 0x2000, 0, 0}, //pool 10-13, mmu page 13 - { (uint8_t *)0x3FFDC000, 0x2000, 0, 0}, //pool 10-13, mmu page 14 - { (uint8_t *)0x3FFDE000, 0x2000, 0, 0}, //pool 10-13, mmu page 15 - { (uint8_t *)0x3FFE0000, 0x4000, 1, 0x400BC000}, //pool 9 blk 1 - { (uint8_t *)0x3FFE4000, 0x4000, 1, 0x400B8000}, //pool 9 blk 0 - { (uint8_t *)0x3FFE8000, 0x8000, 1, 0x400B0000}, //pool 8 <- can be remapped to ROM, used for MAC dump - { (uint8_t *)0x3FFF0000, 0x8000, 1, 0x400A8000}, //pool 7 <- can be used for MAC dump - { (uint8_t *)0x3FFF8000, 0x4000, 1, 0x400A4000}, //pool 6 blk 1 <- can be used as trace memory - { (uint8_t *)0x3FFFC000, 0x4000, 1, 0x400A0000}, //pool 6 blk 0 <- can be used as trace memory - { (uint8_t *)0x40070000, 0x8000, 2, 0}, //pool 0 - { (uint8_t *)0x40078000, 0x8000, 2, 0}, //pool 1 - { (uint8_t *)0x40080000, 0x2000, 2, 0}, //pool 2-5, mmu page 0 - { (uint8_t *)0x40082000, 0x2000, 2, 0}, //pool 2-5, mmu page 1 - { (uint8_t *)0x40084000, 0x2000, 2, 0}, //pool 2-5, mmu page 2 - { (uint8_t *)0x40086000, 0x2000, 2, 0}, //pool 2-5, mmu page 3 - { (uint8_t *)0x40088000, 0x2000, 2, 0}, //pool 2-5, mmu page 4 - { (uint8_t *)0x4008A000, 0x2000, 2, 0}, //pool 2-5, mmu page 5 - { (uint8_t *)0x4008C000, 0x2000, 2, 0}, //pool 2-5, mmu page 6 - { (uint8_t *)0x4008E000, 0x2000, 2, 0}, //pool 2-5, mmu page 7 - { (uint8_t *)0x40090000, 0x2000, 2, 0}, //pool 2-5, mmu page 8 - { (uint8_t *)0x40092000, 0x2000, 2, 0}, //pool 2-5, mmu page 9 - { (uint8_t *)0x40094000, 0x2000, 2, 0}, //pool 2-5, mmu page 10 - { (uint8_t *)0x40096000, 0x2000, 2, 0}, //pool 2-5, mmu page 11 - { (uint8_t *)0x40098000, 0x2000, 2, 0}, //pool 2-5, mmu page 12 - { (uint8_t *)0x4009A000, 0x2000, 2, 0}, //pool 2-5, mmu page 13 - { (uint8_t *)0x4009C000, 0x2000, 2, 0}, //pool 2-5, mmu page 14 - { (uint8_t *)0x4009E000, 0x2000, 2, 0}, //pool 2-5, mmu page 15 - { NULL, 0, 0, 0} //end + { (uint8_t *)0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available + { (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code + { (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- can be used for BT + { (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- can be used for BT + { (uint8_t *)0x3FFC0000, 0x2000, 0, 0}, //pool 10-13, mmu page 0 + { (uint8_t *)0x3FFC2000, 0x2000, 0, 0}, //pool 10-13, mmu page 1 + { (uint8_t *)0x3FFC4000, 0x2000, 0, 0}, //pool 10-13, mmu page 2 + { (uint8_t *)0x3FFC6000, 0x2000, 0, 0}, //pool 10-13, mmu page 3 + { (uint8_t *)0x3FFC8000, 0x2000, 0, 0}, //pool 10-13, mmu page 4 + { (uint8_t *)0x3FFCA000, 0x2000, 0, 0}, //pool 10-13, mmu page 5 + { (uint8_t *)0x3FFCC000, 0x2000, 0, 0}, //pool 10-13, mmu page 6 + { (uint8_t *)0x3FFCE000, 0x2000, 0, 0}, //pool 10-13, mmu page 7 + { (uint8_t *)0x3FFD0000, 0x2000, 0, 0}, //pool 10-13, mmu page 8 + { (uint8_t *)0x3FFD2000, 0x2000, 0, 0}, //pool 10-13, mmu page 9 + { (uint8_t *)0x3FFD4000, 0x2000, 0, 0}, //pool 10-13, mmu page 10 + { (uint8_t *)0x3FFD6000, 0x2000, 0, 0}, //pool 10-13, mmu page 11 + { (uint8_t *)0x3FFD8000, 0x2000, 0, 0}, //pool 10-13, mmu page 12 + { (uint8_t *)0x3FFDA000, 0x2000, 0, 0}, //pool 10-13, mmu page 13 + { (uint8_t *)0x3FFDC000, 0x2000, 0, 0}, //pool 10-13, mmu page 14 + { (uint8_t *)0x3FFDE000, 0x2000, 0, 0}, //pool 10-13, mmu page 15 + { (uint8_t *)0x3FFE0000, 0x4000, 1, 0x400BC000}, //pool 9 blk 1 + { (uint8_t *)0x3FFE4000, 0x4000, 1, 0x400B8000}, //pool 9 blk 0 + { (uint8_t *)0x3FFE8000, 0x8000, 1, 0x400B0000}, //pool 8 <- can be remapped to ROM, used for MAC dump + { (uint8_t *)0x3FFF0000, 0x8000, 1, 0x400A8000}, //pool 7 <- can be used for MAC dump + { (uint8_t *)0x3FFF8000, 0x4000, 1, 0x400A4000}, //pool 6 blk 1 <- can be used as trace memory + { (uint8_t *)0x3FFFC000, 0x4000, 1, 0x400A0000}, //pool 6 blk 0 <- can be used as trace memory + { (uint8_t *)0x40070000, 0x8000, 2, 0}, //pool 0 + { (uint8_t *)0x40078000, 0x8000, 2, 0}, //pool 1 + { (uint8_t *)0x40080000, 0x2000, 2, 0}, //pool 2-5, mmu page 0 + { (uint8_t *)0x40082000, 0x2000, 2, 0}, //pool 2-5, mmu page 1 + { (uint8_t *)0x40084000, 0x2000, 2, 0}, //pool 2-5, mmu page 2 + { (uint8_t *)0x40086000, 0x2000, 2, 0}, //pool 2-5, mmu page 3 + { (uint8_t *)0x40088000, 0x2000, 2, 0}, //pool 2-5, mmu page 4 + { (uint8_t *)0x4008A000, 0x2000, 2, 0}, //pool 2-5, mmu page 5 + { (uint8_t *)0x4008C000, 0x2000, 2, 0}, //pool 2-5, mmu page 6 + { (uint8_t *)0x4008E000, 0x2000, 2, 0}, //pool 2-5, mmu page 7 + { (uint8_t *)0x40090000, 0x2000, 2, 0}, //pool 2-5, mmu page 8 + { (uint8_t *)0x40092000, 0x2000, 2, 0}, //pool 2-5, mmu page 9 + { (uint8_t *)0x40094000, 0x2000, 2, 0}, //pool 2-5, mmu page 10 + { (uint8_t *)0x40096000, 0x2000, 2, 0}, //pool 2-5, mmu page 11 + { (uint8_t *)0x40098000, 0x2000, 2, 0}, //pool 2-5, mmu page 12 + { (uint8_t *)0x4009A000, 0x2000, 2, 0}, //pool 2-5, mmu page 13 + { (uint8_t *)0x4009C000, 0x2000, 2, 0}, //pool 2-5, mmu page 14 + { (uint8_t *)0x4009E000, 0x2000, 2, 0}, //pool 2-5, mmu page 15 + { NULL, 0, 0, 0} //end }; //Modify regions array to disable the given range of memory. static void disable_mem_region(void *from, void *to) { - int i; - //Align from and to on word boundaries - from=(void*)((uint32_t)from&~3); - to=(void*)(((uint32_t)to+3)&~3); - for (i=0; regions[i].xSizeInBytes!=0; i++) { - void *regStart=regions[i].pucStartAddress; - void *regEnd=regions[i].pucStartAddress+regions[i].xSizeInBytes; - if (regStart>=from && regEnd<=to) { - //Entire region falls in the range. Disable entirely. - regions[i].xTag=-1; - } else if (regStart>=from && regEnd>to && regStartfrom && regEnd<=to) { - //End of the region falls in the range. Modify length. - regions[i].xSizeInBytes-=(uint8_t *)regEnd-(uint8_t *)from; - } else if (regStartto) { - //Range punches a hole in the region! We do not support this. - ESP_EARLY_LOGE(TAG, "region %d: hole punching is not supported!", i); - regions[i].xTag=-1; //Just disable memory region. That'll teach them! - } - } + int i; + //Align from and to on word boundaries + from=(void*)((uint32_t)from&~3); + to=(void*)(((uint32_t)to+3)&~3); + for (i=0; regions[i].xSizeInBytes!=0; i++) { + void *regStart=regions[i].pucStartAddress; + void *regEnd=regions[i].pucStartAddress+regions[i].xSizeInBytes; + if (regStart>=from && regEnd<=to) { + //Entire region falls in the range. Disable entirely. + regions[i].xTag=-1; + } else if (regStart>=from && regEnd>to && regStartfrom && regEnd<=to) { + //End of the region falls in the range. Modify length. + regions[i].xSizeInBytes-=(uint8_t *)regEnd-(uint8_t *)from; + } else if (regStartto) { + //Range punches a hole in the region! We do not support this. + ESP_EARLY_LOGE(TAG, "region %d: hole punching is not supported!", i); + regions[i].xTag=-1; //Just disable memory region. That'll teach them! + } + } } @@ -170,52 +170,56 @@ ToDo: The regions are different when stuff like trace memory, BT, ... is used. M Same with loading of apps. Same with using SPI RAM. */ void heap_alloc_caps_init() { - int i; - //Disable the bits of memory where this code is loaded. - disable_mem_region(&_bss_start, &_heap_start); - disable_mem_region((void*)0x3ffae000, (void*)0x3ffb0000); //knock out ROM data region - disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region - disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region - disable_mem_region((void*)0x40080000, (void*)0x400a0000); //pool 2-5 + int i; + //Disable the bits of memory where this code is loaded. + disable_mem_region(&_bss_start, &_heap_start); + disable_mem_region((void*)0x3ffae000, (void*)0x3ffb0000); //knock out ROM data region + disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region + disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region + disable_mem_region((void*)0x40080000, (void*)0x400a0000); //pool 2-5 - // TODO: this region should be checked, since we don't need to knock out all region finally - disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region + // TODO: this region should be checked, since we don't need to knock out all region finally + disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region #if CONFIG_MEMMAP_BT - disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT data region + disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT data region #endif #if CONFIG_MEMMAP_TRACEMEM - disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region +#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS + disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region +#else + disable_mem_region((void*)0x3fff8000, (void*)0x3fffc000); //knock out trace mem region +#endif #endif #if 0 - enable_spi_sram(); + enable_spi_sram(); #else - disable_mem_region((void*)0x3f800000, (void*)0x3f820000); //SPI SRAM not installed + disable_mem_region((void*)0x3f800000, (void*)0x3f820000); //SPI SRAM not installed #endif - //The heap allocator will treat every region given to it as separate. In order to get bigger ranges of contiguous memory, - //it's useful to coalesce adjacent regions that have the same tag. + //The heap allocator will treat every region given to it as separate. In order to get bigger ranges of contiguous memory, + //it's useful to coalesce adjacent regions that have the same tag. - for (i=1; regions[i].xSizeInBytes!=0; i++) { - if (regions[i].pucStartAddress == (regions[i-1].pucStartAddress + regions[i-1].xSizeInBytes) && - regions[i].xTag == regions[i-1].xTag ) { - regions[i-1].xTag=-1; - regions[i].pucStartAddress=regions[i-1].pucStartAddress; - regions[i].xSizeInBytes+=regions[i-1].xSizeInBytes; - } - } + for (i=1; regions[i].xSizeInBytes!=0; i++) { + if (regions[i].pucStartAddress == (regions[i-1].pucStartAddress + regions[i-1].xSizeInBytes) && + regions[i].xTag == regions[i-1].xTag ) { + regions[i-1].xTag=-1; + regions[i].pucStartAddress=regions[i-1].pucStartAddress; + regions[i].xSizeInBytes+=regions[i-1].xSizeInBytes; + } + } - ESP_EARLY_LOGI(TAG, "Initializing heap allocator:"); - for (i=0; regions[i].xSizeInBytes!=0; i++) { - if (regions[i].xTag != -1) { - ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %d", i, - (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag); - } - } - //Initialize the malloc implementation. - vPortDefineHeapRegionsTagged( regions ); + ESP_EARLY_LOGI(TAG, "Initializing heap allocator:"); + for (i=0; regions[i].xSizeInBytes!=0; i++) { + if (regions[i].xTag != -1) { + ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %d", i, + (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag); + } + } + //Initialize the malloc implementation. + vPortDefineHeapRegionsTagged( regions ); } /* @@ -223,7 +227,7 @@ Standard malloc() implementation. Will return ho-hum byte-accessible data memory */ void *pvPortMalloc( size_t xWantedSize ) { - return pvPortMallocCaps( xWantedSize, MALLOC_CAP_8BIT ); + return pvPortMallocCaps( xWantedSize, MALLOC_CAP_8BIT ); } /* @@ -231,30 +235,30 @@ Routine to allocate a bit of memory with certain capabilities. caps is a bitfiel */ void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps ) { - int prio; - int tag, j; - void *ret=NULL; - uint32_t remCaps; - for (prio=0; prio + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define ESP_PARTITION_TABLE_ADDR 0x8000 +#define ESP_PARTITION_MAGIC 0x50AA + +/* OTA selection structure (two copies in the OTA data partition.) + Size of 32 bytes is friendly to flash encryption */ +typedef struct { + uint32_t ota_seq; + uint8_t seq_label[24]; + uint32_t crc; /* CRC32 of ota_seq field only */ +} esp_ota_select_entry_t; + + +typedef struct { + uint32_t offset; + uint32_t size; +} esp_partition_pos_t; + +/* Structure which describes the layout of partition table entry. + * See docs/partition_tables.rst for more information about individual fields. + */ +typedef struct { + uint16_t magic; + uint8_t type; + uint8_t subtype; + esp_partition_pos_t pos; + uint8_t label[16]; + uint8_t reserved[4]; +} esp_partition_info_t; + + +#ifdef __cplusplus +} +#endif + +#endif //__ESP_BIN_TYPES_H__ diff --git a/components/esp32/include/esp_freertos_hooks.h b/components/esp32/include/esp_freertos_hooks.h new file mode 100644 index 0000000000..45a1649723 --- /dev/null +++ b/components/esp32/include/esp_freertos_hooks.h @@ -0,0 +1,83 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP_FREERTOS_HOOKS_H__ +#define __ESP_FREERTOS_HOOKS_H__ + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + Definitions for the tickhook and idlehook callbacks +*/ +typedef bool (*esp_freertos_idle_cb_t)(); +typedef void (*esp_freertos_tick_cb_t)(); + +/** + * @brief Register a callback to be called on the freertos idle hook + * The callback should return true if it's okay for the core to + * sleep until an interrupt (or FreeRTOS tick) happens and false + * if it should be called again as fast as possible. + * + * @warning Idle callbacks MUST NOT, UNDER ANY CIRCUMSTANCES, CALL + * A FUNCTION THAT MIGHT BLOCK. + * + * @param esp_freertos_idle_cb_t new_idle_cb : Callback to be called + * + * @return ESP_OK : Callback registered + * @return ESP_ERR_NO_MEM : No more space to register hook + */ +esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb); + +/** + * @brief Register a callback to be called on the freertos tick hook + * + * @param esp_freertos_tick_cb_t new_tick_cb : Callback to be called + * + * @return ESP_OK : Callback registered + * @return ESP_ERR_NO_MEM : No more space to register hook + */ +esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t tick_cb); + + +/** + * @brief Unregister an idle callback registered earlier + * + * @param esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered + * + * @return void + */ +void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb); + + +/** + * @brief Unregister a tick callback registered earlier + * + * @param esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered + * + * @return void + */ +void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb); + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/components/freertos/gdbstub.h b/components/esp32/include/esp_gdbstub.h similarity index 93% rename from components/freertos/gdbstub.h rename to components/esp32/include/esp_gdbstub.h index 5e97213c92..bc26f2941a 100644 --- a/components/freertos/gdbstub.h +++ b/components/esp32/include/esp_gdbstub.h @@ -17,6 +17,6 @@ #include #include "freertos/xtensa_api.h" -void gdbstubPanicHandler(XtExcFrame *frame); +void esp_gdbstub_panic_handler(XtExcFrame *frame); #endif \ No newline at end of file diff --git a/components/esp32/heap_alloc_caps.h b/components/esp32/include/esp_heap_alloc_caps.h similarity index 100% rename from components/esp32/heap_alloc_caps.h rename to components/esp32/include/esp_heap_alloc_caps.h diff --git a/components/esp32/include/esp_int_wdt.h b/components/esp32/include/esp_int_wdt.h new file mode 100644 index 0000000000..4387400396 --- /dev/null +++ b/components/esp32/include/esp_int_wdt.h @@ -0,0 +1,60 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP_INT_WDT_H +#define __ESP_INT_WDT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup Watchdog_APIs + * @{ + */ + +/* +This routine enables a watchdog to catch instances of processes disabling +interrupts for too long, or code within interrupt handlers taking too long. +It does this by setting up a watchdog which gets fed from the FreeRTOS +task switch interrupt. When this watchdog times out, initially it will call +a high-level interrupt routine that will panic FreeRTOS in order to allow +for forensic examination of the state of the CPU. When this interrupt +handler is not called and the watchdog times out a second time, it will +reset the SoC. + +This uses the TIMERG1 WDT. +*/ + + +/** + * @brief Initialize the interrupt watchdog. This is called in the init code if + * the interrupt watchdog is enabled in menuconfig. + * + * @param null + * + * @return null + */ +void esp_int_wdt_init(); + + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/components/esp32/include/esp_panic.h b/components/esp32/include/esp_panic.h new file mode 100644 index 0000000000..6aba6c5f48 --- /dev/null +++ b/components/esp32/include/esp_panic.h @@ -0,0 +1,21 @@ +#ifndef PANIC_H +#define PANIC_H + + +#define PANIC_RSN_NONE 0 +#define PANIC_RSN_DEBUGEXCEPTION 1 +#define PANIC_RSN_DOUBLEEXCEPTION 2 +#define PANIC_RSN_KERNELEXCEPTION 3 +#define PANIC_RSN_COPROCEXCEPTION 4 +#define PANIC_RSN_INTWDT_CPU0 5 +#define PANIC_RSN_INTWDT_CPU1 6 +#define PANIC_RSN_MAX 6 + + +#ifndef __ASSEMBLER__ + +void esp_set_breakpoint_if_jtag(void *fn); + +#endif + +#endif \ No newline at end of file diff --git a/components/esp32/include/esp_system.h b/components/esp32/include/esp_system.h index 84133366d7..d416e23d07 100644 --- a/components/esp32/include/esp_system.h +++ b/components/esp32/include/esp_system.h @@ -32,6 +32,13 @@ extern "C" { * @{ */ +/** + * @attention application don't need to call this function anymore. It do nothing and will + * be removed in future version. + */ +void system_init(void) __attribute__ ((deprecated)); + + /** * @brief Get information of the SDK version. * @@ -169,8 +176,6 @@ bool system_rtc_mem_write(uint16_t dst, const void *src, uint16_t n); esp_err_t system_efuse_read_mac(uint8_t mac[6]); -void system_init(void); - /** * @} */ diff --git a/components/esp32/include/esp_task_wdt.h b/components/esp32/include/esp_task_wdt.h new file mode 100644 index 0000000000..bbc4995674 --- /dev/null +++ b/components/esp32/include/esp_task_wdt.h @@ -0,0 +1,83 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP_TASK_WDT_H +#define __ESP_TASK_WDT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup Watchdog_APIs Watchdog APIs + * @brief Watchdog APIs + */ + +/** @addtogroup Watchdog_APIs + * @{ + */ + +/* +This routine enables a more general-purpose task watchdog: tasks can individually +feed the watchdog and the watchdog will bark if one or more tasks haven't fed the +watchdog within the specified time. Optionally, the idle tasks can also configured +to feed the watchdog in a similar fashion, to detect CPU starvation. + +This uses the TIMERG0 WDT. +*/ + + +/** + * @brief Initialize the task watchdog. This is called in the init code, if the + * task watchdog is enabled in menuconfig. + * + * @param null + * + * @return null + */ +void esp_task_wdt_init(); + +/** + * @brief Feed the watchdog. After the first feeding session, the watchdog will expect the calling + * task to keep feeding the watchdog until task_wdt_delete() is called. + * + * @param null + * + * @return null + */ + +void esp_task_wdt_feed(); + + +/** + * @brief Delete the watchdog for the current task. + * + * @param null + * + * @return null + */ +void esp_task_wdt_delete(); + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + + + +#endif \ No newline at end of file diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index 12378f3346..88ea0d9a65 100644 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -70,6 +70,24 @@ extern "C" { #endif +#define ESP_ERR_WIFI_OK ESP_OK /*!< No error */ +#define ESP_ERR_WIFI_FAIL ESP_FAIL /*!< General fail code */ +#define ESP_ERR_WIFI_NO_MEM ESP_ERR_NO_MEM /*!< Out of memory */ +#define ESP_ERR_WIFI_ARG ESP_ERR_INVALID_ARG /*!< Invalid argument */ +#define ESP_ERR_WIFI_NOT_SUPPORT ESP_ERR_NOT_SUPPORTED /*!< Indicates that API is not supported yet */ + +#define ESP_ERR_WIFI_NOT_INIT (ESP_ERR_WIFI_BASE + 1) /*!< WiFi driver is not installed by esp_wifi_init */ +#define ESP_ERR_WIFI_NOT_START (ESP_ERR_WIFI_BASE + 2) /*!< WiFi driver is not started by esp_wifi_start */ +#define ESP_ERR_WIFI_IF (ESP_ERR_WIFI_BASE + 3) /*!< WiFi interface error */ +#define ESP_ERR_WIFI_MODE (ESP_ERR_WIFI_BASE + 4) /*!< WiFi mode error */ +#define ESP_ERR_WIFI_STATE (ESP_ERR_WIFI_BASE + 5) /*!< WiFi internal state error */ +#define ESP_ERR_WIFI_CONN (ESP_ERR_WIFI_BASE + 6) /*!< WiFi internal control block of station or soft-AP error */ +#define ESP_ERR_WIFI_NVS (ESP_ERR_WIFI_BASE + 7) /*!< WiFi internal NVS module error */ +#define ESP_ERR_WIFI_MAC (ESP_ERR_WIFI_BASE + 8) /*!< MAC address is invalid */ +#define ESP_ERR_WIFI_SSID (ESP_ERR_WIFI_BASE + 9) /*!< SSID is invalid */ +#define ESP_ERR_WIFI_PASSWORD (ESP_ERR_WIFI_BASE + 10) /*!< Passord is invalid */ +#define ESP_ERR_WIFI_TIMEOUT (ESP_ERR_WIFI_BASE + 11) /*!< Timeout error */ + typedef struct { system_event_handler_t event_handler; /**< WiFi event handler */ } wifi_init_config_t; @@ -92,8 +110,10 @@ typedef struct { * * @param wifi_init_config_t *config : provide WiFi init configuration * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NO_MEM : out of memory + * - others : refer to error code esp_err.h */ esp_err_t esp_wifi_init(wifi_init_config_t *config); @@ -104,7 +124,6 @@ esp_err_t esp_wifi_init(wifi_init_config_t *config); * @attention 1. This API should be called if you want to remove WiFi driver from the system * * @return ESP_OK : succeed - * @return others : fail */ esp_err_t esp_wifi_deinit(void); @@ -116,8 +135,11 @@ esp_err_t esp_wifi_deinit(void); * * @param wifi_mode_t mode : WiFi operating modes: * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - others : refer to error code in esp_err.h */ esp_err_t esp_wifi_set_mode(wifi_mode_t mode); @@ -126,8 +148,10 @@ esp_err_t esp_wifi_set_mode(wifi_mode_t mode); * * @param wifi_mode_t *mode : store current WiFi mode * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument */ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode); @@ -139,8 +163,13 @@ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode); * * @param null * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_NO_MEM : out of memory + * - ESP_ERR_WIFI_CONN : WiFi internal error, station or soft-AP control block wrong + * - ESP_ERR_WIFI_FAIL : other WiFi internal errors */ esp_err_t esp_wifi_start(void); @@ -152,8 +181,9 @@ esp_err_t esp_wifi_start(void); * * @param null * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init */ esp_err_t esp_wifi_stop(void); @@ -165,8 +195,12 @@ esp_err_t esp_wifi_stop(void); * * @param null * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_CONN : WiFi internal error, station or soft-AP control block wrong + * - ESP_ERR_WIFI_SSID : SSID of AP which station connects is invalid */ esp_err_t esp_wifi_connect(void); @@ -175,8 +209,11 @@ esp_err_t esp_wifi_connect(void); * * @param null * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_FAIL : other WiFi internal errors */ esp_err_t esp_wifi_disconnect(void); @@ -185,20 +222,25 @@ esp_err_t esp_wifi_disconnect(void); * * @param null * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - others : fail */ esp_err_t esp_wifi_clear_fast_connect(void); /** - * @brief Kick the all station or associated id equals to aid + * @brief deauthenticate all stations or associated id equals to aid * - * @param uint16_t aid : when aid is 0, kick all stations, otherwise kick station whose associated id is aid + * @param uint16_t aid : when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_MODE : WiFi mode is wrong */ -esp_err_t esp_wifi_kick_station(uint16_t aid); +esp_err_t esp_wifi_deauth_sta(uint16_t aid); /** * @brief Scan all available APs. @@ -211,8 +253,12 @@ esp_err_t esp_wifi_kick_station(uint16_t aid); * @param bool block : if block is true, this API will block the caller until the scan is done, otherwise * it will return immediately * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_TIMEOUT : blocking scan is timeout + * - others : refer to error code in esp_err.h */ esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf, bool block); @@ -220,8 +266,10 @@ esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf, bool block); * @brief Stop the scan in process * * @param null - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start */ esp_err_t esp_wifi_scan_stop(void); @@ -232,30 +280,48 @@ esp_err_t esp_wifi_scan_stop(void); * * @attention This API can only be called when the scan is completed, otherwise it may get wrong value * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_ARG : invalid argument */ -esp_err_t esp_wifi_get_ap_num(uint16_t *number); +esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number); /** * @brief Get AP list found in last scan * - * @param uint16_t *number : as input param, it stores max AP number ap_list can hold, as output param, it store + * @param uint16_t *number : as input param, it stores max AP number ap_records can hold, as output param, it store the actual AP number this API returns - * @param wifi_ap_list_t *ap_list : a list to hold the found APs + * @param wifi_ap_record_t *ap_records: wifi_ap_record_t array to hold the found APs * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_NO_MEM : out of memory */ -esp_err_t esp_wifi_get_ap_list(uint16_t *number, wifi_ap_list_t *ap_list); +esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records); + + +/** + * @brief Get information of AP associated with ESP32 station + * + * @param wifi_ap_record_t *ap_info: the wifi_ap_record_t to hold station assocated AP + * + * @return + * - ESP_OK : succeed + * - others : fail + */ +esp_err_t esp_wifi_sta_get_ap_info(wifi_ap_record_t *ap_info); /** * @brief Set current power save type * * @param wifi_ps_type_t type : power save type * - * @return ESP_OK : succeed - * @return others : fail + * @return ESP_ERR_WIFI_NOT_SUPPORT : not support yet */ esp_err_t esp_wifi_set_ps(wifi_ps_type_t type); @@ -264,8 +330,7 @@ esp_err_t esp_wifi_set_ps(wifi_ps_type_t type); * * @param wifi_ps_type_t *type : store current power save type * - * @return ESP_OK : succeed - * @return others : fail + * @return ESP_ERR_WIFI_NOT_SUPPORT : not support yet */ esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type); @@ -278,8 +343,11 @@ esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type); * @param wifi_interface_t ifx : interfaces * @param uint8_t protocol : WiFi protocol bitmap * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF : invalid interface + * - others : refer to erro code in esp_err.h */ esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap); @@ -289,8 +357,12 @@ esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap); * @param wifi_interface_t ifx : interfaces * @param uint8_t protocol : store current WiFi protocol bitmap of interface ifx * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF : invalid interface + * - ESP_ERR_WIFI_ARG : invalid argument + * - others : refer to error code in esp_err.h */ esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap); @@ -303,8 +375,12 @@ esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap); * @param wifi_interface_t ifx : interface to be configured * @param wifi_bandwidth_t bw : bandwidth * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF : invalid interface + * - ESP_ERR_WIFI_ARG : invalid argument + * - others : refer to error code in esp_err.h */ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw); @@ -316,8 +392,11 @@ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw); * @param wifi_interface_t ifx : interface to be configured * @param wifi_bandwidth_t *bw : store bandwidth of interface ifx * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF : invalid interface + * - ESP_ERR_WIFI_ARG : invalid argument */ esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw); @@ -329,8 +408,11 @@ esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw); * @param uint8_t primary : for HT20, primary is the channel number, for HT40, primary is the primary channel * @param wifi_second_chan_t second : for HT20, second is ignored, for HT40, second is the second channel * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF : invalid interface + * - ESP_ERR_WIFI_ARG : invalid argument */ esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second); @@ -342,8 +424,10 @@ esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second); * @param uint8_t *primary : store current primary channel * @param wifi_second_chan_t *second : store current second channel * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument */ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); @@ -353,8 +437,11 @@ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); * * @param wifi_country_t country : country type * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - others : refer to error code in esp_err.h */ esp_err_t esp_wifi_set_country(wifi_country_t country); @@ -363,8 +450,10 @@ esp_err_t esp_wifi_set_country(wifi_country_t country); * * @param wifi_country_t country : store current country * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument */ esp_err_t esp_wifi_get_country(wifi_country_t *country); @@ -379,8 +468,14 @@ esp_err_t esp_wifi_get_country(wifi_country_t *country); * @param wifi_interface_t ifx : interface * @param uint8 mac[6]: the MAC address. * - * @return true : succeed - * @return false : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_IF : invalid interface + * - ESP_ERR_WIFI_MAC : invalid mac address + * - ESP_ERR_WIFI_MODE : WiFi mode is wrong + * - others : refer to error code in esp_err.h */ esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6]); @@ -389,8 +484,11 @@ esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6]); * * @param uint8_t mac[6] : store mac of this interface ifx * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_IF : invalid interface */ esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]); @@ -402,8 +500,7 @@ esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]); * @param void *buf : the data received * @param uint16_t len : data length * - * @return ESP_OK : succeed - * @return others : fail + * @return none */ typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len); @@ -414,8 +511,9 @@ typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len); * * @param wifi_promiscuous_cb_t cb : callback * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init */ esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); @@ -424,8 +522,9 @@ esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); * * @param bool promiscuous : false - disable / true - enable * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init */ esp_err_t esp_wifi_set_promiscuous(bool en); @@ -434,8 +533,10 @@ esp_err_t esp_wifi_set_promiscuous(bool en); * * @param bool *enable : store the current status of promiscuous mode * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument */ esp_err_t esp_wifi_get_promiscuous(bool *en); @@ -450,8 +551,15 @@ esp_err_t esp_wifi_get_promiscuous(bool *en); * @param wifi_interface_t ifx : interface * @param wifi_config_t *conf : station or soft-AP configuration * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_IF : invalid interface + * - ESP_ERR_WIFI_MODE : invalid mode + * - ESP_ERR_WIFI_PASSWORD : invalid password + * - ESP_ERR_WIFI_NVS : WiFi internal NVS error + * - others : refer to the erro code in esp_err.h */ esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf); @@ -461,8 +569,11 @@ esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf); * @param wifi_interface_t ifx : interface * @param wifi_config_t *conf : station or soft-AP configuration * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_IF : invalid interface */ esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf); @@ -471,14 +582,17 @@ esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf); * * @attention SSC only API * - * @param struct station_info **station : station list + * @param wifi_sta_list_t *sta: station list * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_MODE : WiFi mode is wrong + * - ESP_ERR_WIFI_CONN : WiFi internal error, the station/soft-AP control block is invalid */ -esp_err_t esp_wifi_get_station_list(struct station_info **station); +esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta); -esp_err_t esp_wifi_free_station_list(void); /** * @brief Set the WiFi API configuration storage type @@ -487,42 +601,24 @@ esp_err_t esp_wifi_free_station_list(void); * * @param wifi_storage_t storage : storage type * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument */ esp_err_t esp_wifi_set_storage(wifi_storage_t storage); -/** - * @brief The WiFi RX callback function - * - * Each time the WiFi need to forward the packets to high layer, the callback function will be called - * - */ -typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void *eb); - -/** - * @brief Set the WiFi RX callback - * - * @attention 1. Currently we support only one RX callback for each interface - * - * @param wifi_interface_t ifx : interface - * @param wifi_rxcb_t fn : WiFi RX callback - * - * @return ESP_OK : succeed - * @return others : fail - */ -esp_err_t esp_wifi_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn); - /** * @brief Set auto connect * The default value is true * - * @attention 1. - * * @param bool en : true - enable auto connect / false - disable auto connect * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_MODE : WiFi internal error, the station/soft-AP control block is invalid + * - others : refer to error code in esp_err.h */ esp_err_t esp_wifi_set_auto_connect(bool en); @@ -531,8 +627,10 @@ esp_err_t esp_wifi_set_auto_connect(bool en); * * @param bool *en : store current auto connect configuration * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument */ esp_err_t esp_wifi_get_auto_connect(bool *en); @@ -549,8 +647,11 @@ esp_err_t esp_wifi_get_auto_connect(bool *en); 1 - WIFI_VND_IE_ID_1 * @param uint8_t *vnd_ie : pointer to a vendor specific element * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_ERR_WIFI_NO_MEM : out of memory */ esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, uint8_t *vnd_ie); @@ -574,8 +675,9 @@ typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const * @param esp_vendor_ie_cb_t cb : callback function * @param void *ctx : reserved * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init */ esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx); diff --git a/components/esp32/include/esp_wifi_internal.h b/components/esp32/include/esp_wifi_internal.h new file mode 100644 index 0000000000..2015b5063d --- /dev/null +++ b/components/esp32/include/esp_wifi_internal.h @@ -0,0 +1,112 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +/* + * All the APIs declared here are internal only APIs, it can only be used by + * espressif internal modules, such as SSC, LWIP, TCPIP adapter etc, espressif + * customers are not recommended to use them. + * + * If someone really want to use specified APIs declared in here, please contact + * espressif AE/developer to make sure you know the limitations or risk of + * the API, otherwise you may get unexpected behavior!!! + * + */ + + +#ifndef __ESP_WIFI_INTERNAL_H__ +#define __ESP_WIFI_INTERNAL_H__ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "rom/queue.h" +#include "esp_err.h" +#include "esp_wifi_types.h" +#include "esp_event.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief get whether the wifi driver is allowed to transmit data or not + * + * @param none + * + * @return true : upper layer should stop to transmit data to wifi driver + * @return false : upper layer can transmit data to wifi driver + */ +bool esp_wifi_internal_tx_is_stop(void); + +/** + * @brief free the rx buffer which allocated by wifi driver + * + * @param void* buffer: rx buffer pointer + * + * @return nonoe + */ +void esp_wifi_internal_free_rx_buffer(void* buffer); + +/** + * @brief transmit the buffer via wifi driver + * + * @param wifi_interface_t wifi_if : wifi interface id + * @param void *buffer : the buffer to be tansmit + * @param u16_t len : the length of buffer + * + * @return + * - ERR_OK : Successfully transmit the buffer to wifi driver + * - ERR_MEM : Out of memory + * - ERR_IF : WiFi driver error + * - ERR_ARG : Invalid argument + */ +int esp_wifi_internal_tx(wifi_interface_t wifi_if, void *buffer, u16_t len); + +/** + * @brief The WiFi RX callback function + * + * Each time the WiFi need to forward the packets to high layer, the callback function will be called + * + */ +typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void *eb); + +/** + * @brief Set the WiFi RX callback + * + * @attention 1. Currently we support only one RX callback for each interface + * + * @param wifi_interface_t ifx : interface + * @param wifi_rxcb_t fn : WiFi RX callback + * + * @return ESP_OK : succeed + * @return others : fail + */ +esp_err_t esp_wifi_internal_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn); + +/** + * @brief Notify WIFI driver that the station got ip successfully + * + * @param none + * + * @return ESP_OK : succeed + * @return others : fail + */ +esp_err_t esp_wifi_internal_set_sta_ip(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_WIFI_H__ */ diff --git a/components/esp32/include/esp_wifi_types.h b/components/esp32/include/esp_wifi_types.h index b3474769e8..fb19aa8fc3 100644 --- a/components/esp32/include/esp_wifi_types.h +++ b/components/esp32/include/esp_wifi_types.h @@ -109,7 +109,7 @@ typedef struct { wifi_second_chan_t second; /**< second channel of AP */ int8_t rssi; /**< signal strength of AP */ wifi_auth_mode_t authmode; /**< authmode of AP */ -} wifi_ap_list_t; +} wifi_ap_record_t; typedef enum { WIFI_PS_NONE, /**< No power save */ @@ -150,10 +150,15 @@ typedef union { wifi_sta_config_t sta; /**< configuration of STA */ } wifi_config_t; -struct station_info { - STAILQ_ENTRY(station_info) next; - uint8_t bssid[6]; -}; +typedef struct { + uint8_t mac[6]; /**< mac address of sta that associated with ESP32 soft-AP */ +}wifi_sta_info_t; + +#define ESP_WIFI_MAX_CONN_NUM (10) /**< max number of stations which can connect to ESP32 soft-AP */ +typedef struct { + wifi_sta_info_t sta[ESP_WIFI_MAX_CONN_NUM]; /**< station list */ + int num; /**< number of station that associated with ESP32 soft-AP */ +}wifi_sta_list_t; typedef enum { WIFI_STORAGE_FLASH, /**< all configuration will strore in both memory and flash */ diff --git a/components/esp32/include/esp_wps.h b/components/esp32/include/esp_wps.h new file mode 100644 index 0000000000..f95eaa5e2a --- /dev/null +++ b/components/esp32/include/esp_wps.h @@ -0,0 +1,111 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP_WPS_H__ +#define __ESP_WPS_H__ + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup WiFi_APIs WiFi Related APIs + * @brief WiFi APIs + */ + +/** @addtogroup WiFi_APIs + * @{ + */ + +/** \defgroup WPS_APIs WPS APIs + * @brief ESP32 WPS APIs + * + * WPS can only be used when ESP32 station is enabled. + * + */ + +/** @addtogroup WPS_APIs + * @{ + */ + +#define ESP_ERR_WIFI_REGISTRAR (ESP_ERR_WIFI_BASE + 51) /*!< WPS registrar is not supported */ +#define ESP_ERR_WIFI_WPS_TYPE (ESP_ERR_WIFI_BASE + 52) /*!< WPS type error */ +#define ESP_ERR_WIFI_WPS_SM (ESP_ERR_WIFI_BASE + 53) /*!< WPS state machine is not initialized */ + +typedef enum wps_type { + WPS_TYPE_DISABLE = 0, + WPS_TYPE_PBC, + WPS_TYPE_PIN, + WPS_TYPE_MAX, +} wps_type_t; + +/** + * @brief Enable Wi-Fi WPS function. + * + * @attention WPS can only be used when ESP32 station is enabled. + * + * @param wps_type_t wps_type : WPS type, so far only WPS_TYPE_PBC and WPS_TYPE_PIN is supported + * + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid + * - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on + * - ESP_ERR_WIFI_FAIL : wps initialization fails + */ +esp_err_t esp_wifi_wps_enable(wps_type_t wps_type); + +/** + * @brief Disable Wi-Fi WPS function and release resource it taken. + * + * @param null + * + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on + */ +esp_err_t esp_wifi_wps_disable(void); + +/** + * @brief WPS starts to work. + * + * @attention WPS can only be used when ESP32 station is enabled. + * + * @param timeout_ms : maximum blocking time before API return. + * - 0 : non-blocking + * - 1~120000 : blocking time (not supported in IDF v1.0) + * + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid + * - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on + * - ESP_ERR_WIFI_WPS_SM : wps state machine is not initialized + * - ESP_ERR_WIFI_FAIL : wps initialization fails + */ +esp_err_t esp_wifi_wps_start(int timeout_ms); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_WPS_H__ */ diff --git a/components/esp32/include/heap_alloc_caps.h b/components/esp32/include/heap_alloc_caps.h new file mode 100644 index 0000000000..d371ca5ed8 --- /dev/null +++ b/components/esp32/include/heap_alloc_caps.h @@ -0,0 +1,34 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 HEAP_ALLOC_CAPS_H +#define HEAP_ALLOC_CAPS_H + +#define MALLOC_CAP_EXEC (1<<0) //Memory must be able to run executable code +#define MALLOC_CAP_32BIT (1<<1) //Memory must allow for aligned 32-bit data accesses +#define MALLOC_CAP_8BIT (1<<2) //Memory must allow for 8/16/...-bit data accesses +#define MALLOC_CAP_DMA (1<<3) //Memory must be able to accessed by DMA +#define MALLOC_CAP_PID2 (1<<4) //Memory must be mapped to PID2 memory space +#define MALLOC_CAP_PID3 (1<<5) //Memory must be mapped to PID3 memory space +#define MALLOC_CAP_PID4 (1<<6) //Memory must be mapped to PID4 memory space +#define MALLOC_CAP_PID5 (1<<7) //Memory must be mapped to PID5 memory space +#define MALLOC_CAP_PID6 (1<<8) //Memory must be mapped to PID6 memory space +#define MALLOC_CAP_PID7 (1<<9) //Memory must be mapped to PID7 memory space +#define MALLOC_CAP_SPISRAM (1<<10) //Memory must be in SPI SRAM +#define MALLOC_CAP_INVALID (1<<31) //Memory can't be used / list end marker + + +void heap_alloc_caps_init(); +void *pvPortMallocCaps(size_t xWantedSize, uint32_t caps); + +#endif \ No newline at end of file diff --git a/components/esp32/include/rom/secure_boot.h b/components/esp32/include/rom/secure_boot.h index cfeda08933..bd4f32ed95 100644 --- a/components/esp32/include/rom/secure_boot.h +++ b/components/esp32/include/rom/secure_boot.h @@ -25,7 +25,7 @@ void ets_secure_boot_start(void); void ets_secure_boot_finish(void); -void ets_secure_boot_hash(uint32_t *buf); +void ets_secure_boot_hash(const uint32_t *buf); void ets_secure_boot_obtain(void); diff --git a/components/esp32/include/rom/spi_flash.h b/components/esp32/include/rom/spi_flash.h index ba8eebc2ce..1f14c6617a 100644 --- a/components/esp32/include/rom/spi_flash.h +++ b/components/esp32/include/rom/spi_flash.h @@ -218,7 +218,7 @@ void SelectSpiFunction(uint32_t ishspi); void spi_flash_attach(uint32_t ishspi, bool legacy); /** - * @brief SPI Read Flash status register. We use CMD 0x05. + * @brief SPI Read Flash status register. We use CMD 0x05 (RDSR). * Please do not call this function in SDK. * * @param SpiFlashChip *spi : The information for Flash, which is exported from ld file. @@ -232,7 +232,7 @@ void spi_flash_attach(uint32_t ishspi, bool legacy); SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status); /** - * @brief SPI Read Flash status register high 16 bit. We use CMD 0x35. + * @brief SPI Read Flash status register bits 8-15. We use CMD 0x35 (RDSR2). * Please do not call this function in SDK. * * @param SpiFlashChip *spi : The information for Flash, which is exported from ld file. @@ -243,7 +243,7 @@ SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status); * SPI_FLASH_RESULT_ERR : read error. * SPI_FLASH_RESULT_TIMEOUT : read timeout. */ -SpiFlashOpResult SPI_read_status_high(SpiFlashChip *spi, uint32_t *status); +SpiFlashOpResult SPI_read_status_high(uint32_t *status); /** * @brief Write status to Falsh status register. @@ -503,6 +503,12 @@ void SPI_Write_Encrypt_Disable(void); */ SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len); + +/** @brief Global SpiFlashChip structure used by ROM functions + * + */ +extern SpiFlashChip g_rom_flashchip; + /** * @} */ diff --git a/components/esp32/include/soc/cpu.h b/components/esp32/include/soc/cpu.h index c74ba317c8..ee2907493e 100644 --- a/components/esp32/include/soc/cpu.h +++ b/components/esp32/include/soc/cpu.h @@ -15,6 +15,9 @@ #ifndef _SOC_CPU_H #define _SOC_CPU_H +#include +#include +#include #include "xtensa/corebits.h" /* C macros for xtensa special register read/write/exchange */ diff --git a/components/esp32/include/soc/dport_reg.h b/components/esp32/include/soc/dport_reg.h index d65d9edbce..0c43c08740 100644 --- a/components/esp32/include/soc/dport_reg.h +++ b/components/esp32/include/soc/dport_reg.h @@ -3830,6 +3830,11 @@ #define DPORT_DATE_S 0 #define DPORT_DPORT_DATE_VERSION 0x1605190 +/* Flash MMU table for PRO CPU */ +#define DPORT_PRO_FLASH_MMU_TABLE ((volatile uint32_t*) 0x3FF10000) + +/* Flash MMU table for APP CPU */ +#define DPORT_APP_FLASH_MMU_TABLE ((volatile uint32_t*) 0x3FF12000) diff --git a/components/esp32/include/soc/efuse_reg.h b/components/esp32/include/soc/efuse_reg.h index a0f0a07da6..291e3984ee 100644 --- a/components/esp32/include/soc/efuse_reg.h +++ b/components/esp32/include/soc/efuse_reg.h @@ -29,6 +29,16 @@ #define EFUSE_RD_EFUSE_RD_DIS_M ((EFUSE_RD_EFUSE_RD_DIS_V)<<(EFUSE_RD_EFUSE_RD_DIS_S)) #define EFUSE_RD_EFUSE_RD_DIS_V 0xF #define EFUSE_RD_EFUSE_RD_DIS_S 16 + +/* Read disable bits for efuse blocks 1-3 */ +#define EFUSE_RD_DIS_BLK1 (1<<16) +#define EFUSE_RD_DIS_BLK2 (1<<17) +#define EFUSE_RD_DIS_BLK3 (1<<18) +/* Read disable FLASH_CRYPT_CONFIG, CODING_SCHEME & KEY_STATUS + in efuse block 0 +*/ +#define EFUSE_RD_DIS_BLK0_PARTIAL (1<<19) + /* EFUSE_RD_EFUSE_WR_DIS : RO ;bitpos:[15:0] ;default: 16'b0 ; */ /*description: read for efuse_wr_disable*/ #define EFUSE_RD_EFUSE_WR_DIS 0x0000FFFF @@ -36,6 +46,22 @@ #define EFUSE_RD_EFUSE_WR_DIS_V 0xFFFF #define EFUSE_RD_EFUSE_WR_DIS_S 0 +/* Write disable bits */ +#define EFUSE_WR_DIS_RD_DIS (1<<0) /*< disable writing read disable reg */ +#define EFUSE_WR_DIS_WR_DIS (1<<1) /*< disable writing write disable reg */ +#define EFUSE_WR_DIS_FLASH_CRYPT_CNT (1<<2) +#define EFUSE_WR_DIS_MAC_SPI_CONFIG_HD (1<<3) /*< disable writing MAC & SPI config hd efuses */ +#define EFUSE_WR_DIS_XPD_SDIO (1<<5) /*< disable writing SDIO config efuses */ +#define EFUSE_WR_DIS_SPI_PAD_CONFIG (1<<6) /*< disable writing SPI_PAD_CONFIG efuses */ +#define EFUSE_WR_DIS_BLK1 (1<<7) /*< disable writing BLK1 efuses */ +#define EFUSE_WR_DIS_BLK2 (1<<8) /*< disable writing BLK2 efuses */ +#define EFUSE_WR_DIS_BLK3 (1<<9) /*< disable writing BLK3 efuses */ +#define EFUSE_WR_DIS_FLASH_CRYPT_CODING_SCHEME (1<<10) /*< disable writing FLASH_CRYPT_CONFIG and CODING_SCHEME efuses */ +#define EFUSE_WR_DIS_ABS_DONE_0 (1<<12) /*< disable writing ABS_DONE_0 efuse */ +#define EFUSE_WR_DIS_ABS_DONE_1 (1<<13) /*< disable writing ABS_DONE_1 efuse */ +#define EFUSE_WR_DIS_JTAG_DISABLE (1<<14) /*< disable writing JTAG_DISABLE efuse */ +#define EFUSE_WR_DIS_CONSOLE_DL_DISABLE (1<<15) /*< disable writing CONSOLE_DEBUG_DISABLE, DISABLE_DL_ENCRYPT, DISABLE_DL_DECRYPT and DISABLE_DL_CACHE efuses */ + #define EFUSE_BLK0_RDATA1_REG (DR_REG_EFUSE_BASE + 0x004) /* EFUSE_RD_WIFI_MAC_CRC_LOW : RO ;bitpos:[31:0] ;default: 32'b0 ; */ /*description: read for low 32bit WIFI_MAC_Address*/ diff --git a/components/esp32/include/soc/frc_timer_reg.h b/components/esp32/include/soc/frc_timer_reg.h new file mode 100644 index 0000000000..d76199c4f3 --- /dev/null +++ b/components/esp32/include/soc/frc_timer_reg.h @@ -0,0 +1,49 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SOC_FRC_TIMER_REG_H_ +#define _SOC_FRC_TIMER_REG_H_ + +#include "soc.h" + +/** + * These are the register definitions for "legacy" timers + */ + +#define REG_FRC_TIMER_BASE(i) (DR_REG_FRC_TIMER_BASE + i*0x20) + +#define FRC_TIMER_LOAD_REG(i) (REG_FRC_TIMER_BASE(i) + 0x0) // timer load value (23 bit for i==0, 32 bit for i==1) +#define FRC_TIMER_LOAD_VALUE(i) ((i == 0)?0x007FFFFF:0xffffffff) +#define FRC_TIMER_LOAD_VALUE_S 0 + +#define FRC_TIMER_COUNT_REG(i) (REG_FRC_TIMER_BASE(i) + 0x4) // timer count value (23 bit for i==0, 32 bit for i==1) +#define FRC_TIMER_COUNT ((i == 0)?0x007FFFFF:0xffffffff) +#define FRC_TIMER_COUNT_S 0 + +#define FRC_TIMER_CTRL_REG(i) (REG_FRC_TIMER_BASE(i) + 0x8) +#define FRC_TIMER_INT_ENABLE (BIT(8)) // enable interrupt +#define FRC_TIMER_ENABLE (BIT(7)) // enable timer +#define FRC_TIMER_AUTOLOAD (BIT(6)) // enable autoload +#define FRC_TIMER_PRESCALER 0x00000007 // 0: divide by 1, 2: divide by 16, 4: divide by 256 +#define FRC_TIMER_PRESCALER_S 1 +#define FRC_TIMER_EDGE_INT (BIT(0)) // 0: level, 1: edge + +#define FRC_TIMER_INT_REG(i) (REG_FRC_TIMER_BASE(i) + 0xC) +#define FRC_TIMER_INT_CLR (BIT(0)) // clear interrupt + +#define FRC_TIMER_ALARM_REG(i) (REG_FRC_TIMER_BASE(i) + 0x10) // timer alarm value; register only present for i == 1 +#define FRC_TIMER_ALARM 0xFFFFFFFF +#define FRC_TIMER_ALARM_S 0 + +#endif //_SOC_FRC_TIMER_REG_H_ diff --git a/components/esp32/include/soc/io_mux_reg.h b/components/esp32/include/soc/io_mux_reg.h index 208a60703a..de8fe7ec99 100644 --- a/components/esp32/include/soc/io_mux_reg.h +++ b/components/esp32/include/soc/io_mux_reg.h @@ -34,10 +34,41 @@ #define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) #define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) #define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); -#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) -#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) + +/* + * @attention + * The PIN_PULL[UP|DWN]_[EN|DIS]() functions used to exist as macros in previous SDK versions. + * Unfortunately, however, they do not work for some GPIOs on the ESP32 chip, which needs pullups + * and -downs turned on and off through RTC registers. The functions still exist for compatibility + * with older code, but are marked as deprecated in order to generate a warning. + * Please replace them in this fashion: (make sure to include driver/gpio.h as well) + * PIN_PULLUP_EN(GPIO_PIN_MUX_REG[x]) -> gpio_pullup_en(x) + * PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[x]) -> gpio_pullup_dis(x) + * PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[x]) -> gpio_pulldown_en(x) + * PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[x]) -> gpio_pulldown_dis(x) + * +*/ +static inline void __attribute__ ((deprecated)) PIN_PULLUP_DIS(uint32_t PIN_NAME) +{ + REG_CLR_BIT(PIN_NAME, FUN_PU); +} + +static inline void __attribute__ ((deprecated)) PIN_PULLUP_EN(uint32_t PIN_NAME) +{ + REG_SET_BIT(PIN_NAME, FUN_PU); +} + +static inline void __attribute__ ((deprecated)) PIN_PULLDWN_DIS(uint32_t PIN_NAME) +{ + REG_CLR_BIT(PIN_NAME, FUN_PD); +} + +static inline void __attribute__ ((deprecated)) PIN_PULLDWN_EN(uint32_t PIN_NAME) +{ + REG_SET_BIT(PIN_NAME, FUN_PD); +} + + #define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) #define PIN_FUNC_GPIO 2 diff --git a/components/esp32/include/soc/rmt_struct.h b/components/esp32/include/soc/rmt_struct.h index fb4c21055e..511fefa267 100644 --- a/components/esp32/include/soc/rmt_struct.h +++ b/components/esp32/include/soc/rmt_struct.h @@ -231,11 +231,10 @@ typedef volatile struct { struct { union { struct { - uint32_t level1: 1; - uint32_t duration1: 15; - uint32_t level0: 1; uint32_t duration0: 15; - + uint32_t level0: 1; + uint32_t duration1: 15; + uint32_t level1: 1; }; uint32_t val; } data[64]; diff --git a/components/esp32/include/soc/rtc_cntl_reg.h b/components/esp32/include/soc/rtc_cntl_reg.h index 47328611e0..d99cec1864 100644 --- a/components/esp32/include/soc/rtc_cntl_reg.h +++ b/components/esp32/include/soc/rtc_cntl_reg.h @@ -14,6 +14,9 @@ #ifndef _SOC_RTC_CNTL_REG_H_ #define _SOC_RTC_CNTL_REG_H_ +/* The value that needs to be written to RTC_CNTL_WDT_WKEY to write-enable the wdt registers */ +#define RTC_CNTL_WDT_WKEY_VALUE 0x50D83AA1 + #include "soc.h" #define RTC_CNTL_OPTIONS0_REG (DR_REG_RTCCNTL_BASE + 0x0) @@ -236,6 +239,9 @@ #define RTC_CNTL_TIME_VALID_V 0x1 #define RTC_CNTL_TIME_VALID_S 30 +/* frequency of RTC slow clock, Hz */ +#define RTC_CTNL_SLOWCLK_FREQ 150000 + #define RTC_CNTL_TIME0_REG (DR_REG_RTCCNTL_BASE + 0x10) /* RTC_CNTL_TIME_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */ /*description: RTC timer low 32 bits*/ diff --git a/components/esp32/include/soc/soc.h b/components/esp32/include/soc/soc.h index 65698ec856..bec4c85cfc 100755 --- a/components/esp32/include/soc/soc.h +++ b/components/esp32/include/soc/soc.h @@ -149,6 +149,7 @@ #define DR_REG_GPIO_SD_BASE 0x3ff44f00 #define DR_REG_FE2_BASE 0x3ff45000 #define DR_REG_FE_BASE 0x3ff46000 +#define DR_REG_FRC_TIMER_BASE 0x3ff47000 #define DR_REG_RTCCNTL_BASE 0x3ff48000 #define DR_REG_RTCIO_BASE 0x3ff48400 #define DR_REG_SARADC_BASE 0x3ff48800 @@ -282,9 +283,9 @@ * 19 2 extern level * 20 2 extern level * 21 2 extern level - * 22 3 extern edge + * 22 3 extern edge FRC1 timer * 23 3 extern level - * 24 4 extern level + * 24 4 extern level TG1_WDT * 25 4 extern level Reserved Reserved * 26 5 extern level Reserved Reserved * 27 3 extern level Reserved Reserved @@ -302,8 +303,10 @@ #define ETS_T0_WDT_INUM 3 #define ETS_WBB_INUM 4 #define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/ +#define ETS_FRC1_INUM 22 +#define ETS_T1_WDT_INUM 24 -//CPU0 Intrrupt number used in ROM, should be cancelled in SDK +//CPU0 Interrupt number used in ROM, should be cancelled in SDK #define ETS_SLC_INUM 1 #define ETS_UART0_INUM 5 #define ETS_UART1_INUM 5 diff --git a/components/esp32/include/soc/timer_group_reg.h b/components/esp32/include/soc/timer_group_reg.h index 96a5eb7905..2db2a7e3f1 100644 --- a/components/esp32/include/soc/timer_group_reg.h +++ b/components/esp32/include/soc/timer_group_reg.h @@ -15,6 +15,16 @@ #define __TIMG_REG_H__ #include "soc.h" +/* The value that needs to be written to TIMG_WDT_WKEY to write-enable the wdt registers */ +#define TIMG_WDT_WKEY_VALUE 0x50D83AA1 + +/* Possible values for TIMG_WDT_STGx */ +#define TIMG_WDT_STG_SEL_OFF 0 +#define TIMG_WDT_STG_SEL_INT 1 +#define TIMG_WDT_STG_SEL_RESET_CPU 2 +#define TIMG_WDT_STG_SEL_RESET_SYSTEM 3 + + #define REG_TIMG_BASE(i) (DR_REG_TIMERGROUP0_BASE + i*0x1000) #define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000) /* TIMG_T0_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */ diff --git a/components/esp32/include/soc/uart_reg.h b/components/esp32/include/soc/uart_reg.h index 155700b293..8cac4bb832 100644 --- a/components/esp32/include/soc/uart_reg.h +++ b/components/esp32/include/soc/uart_reg.h @@ -18,8 +18,10 @@ #include "soc.h" #define REG_UART_BASE( i ) (DR_REG_UART_BASE + (i) * 0x10000 + ( i > 1 ? 0xe000 : 0 ) ) - +#define REG_UART_AHB_BASE(i) (0x60000000 + (i) * 0x10000 + ( i > 1 ? 0xe000 : 0 ) ) +#define UART_FIFO_AHB_REG(i) (REG_UART_AHB_BASE(i) + 0x0) #define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0) + /* UART_RXFIFO_RD_BYTE : RO ;bitpos:[7:0] ;default: 8'b0 ; */ /*description: This register stores one byte data read by rx fifo.*/ #define UART_RXFIFO_RD_BYTE 0x000000FF diff --git a/components/esp32/int_wdt.c b/components/esp32/int_wdt.c new file mode 100644 index 0000000000..fe3ddab370 --- /dev/null +++ b/components/esp32/int_wdt.c @@ -0,0 +1,100 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "sdkconfig.h" +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include "esp_err.h" +#include "esp_intr.h" +#include "esp_attr.h" +#include "esp_freertos_hooks.h" +#include "soc/timer_group_struct.h" +#include "soc/timer_group_reg.h" + +#include "esp_int_wdt.h" + +#if CONFIG_INT_WDT + + +#define WDT_INT_NUM 24 + + +//Take care: the tick hook can also be called before esp_int_wdt_init() is called. +#if CONFIG_INT_WDT_CHECK_CPU1 +//Not static; the ISR assembly checks this. +bool int_wdt_app_cpu_ticked=false; + +static void IRAM_ATTR tick_hook(void) { + if (xPortGetCoreID()!=0) { + int_wdt_app_cpu_ticked=true; + } else { + //Only feed wdt if app cpu also ticked. + if (int_wdt_app_cpu_ticked) { + TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt + TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset + TIMERG1.wdt_feed=1; + TIMERG1.wdt_wprotect=0; + int_wdt_app_cpu_ticked=false; + } + } +} +#else +static void IRAM_ATTR tick_hook(void) { + if (xPortGetCoreID()!=0) return; + TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt + TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset + TIMERG1.wdt_feed=1; + TIMERG1.wdt_wprotect=0; +} +#endif + + +void esp_int_wdt_init() { + TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS + TIMERG1.wdt_config0.cpu_reset_length=7; //3.2uS + TIMERG1.wdt_config0.level_int_en=1; + TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt + TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system + TIMERG1.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS + //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets + //it to their actual value. + TIMERG1.wdt_config2=10000; + TIMERG1.wdt_config3=10000; + TIMERG1.wdt_config0.en=1; + TIMERG1.wdt_feed=1; + TIMERG1.wdt_wprotect=0; + TIMERG1.int_clr_timers.wdt=1; + TIMERG1.int_ena.wdt=1; + esp_register_freertos_tick_hook(tick_hook); + ESP_INTR_DISABLE(WDT_INT_NUM); + intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM); + //We do not register a handler for the interrupt because it is interrupt level 4 which + //is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for + //this interrupt. + ESP_INTR_ENABLE(WDT_INT_NUM); +} + + + +#endif \ No newline at end of file diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index a3c6367840..aafafbb495 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -3,8 +3,38 @@ ENTRY(call_start_cpu0); SECTIONS { + /* RTC fast memory holds RTC wake stub code, + including from any source file named rtc_wake_stub*.c + */ + .rtc.text : + { + . = ALIGN(4); + *(.rtc.literal .rtc.text) + *rtc_wake_stub*.o(.literal .text .literal.* .text.*) + } >rtc_iram_seg + + /* RTC slow memory holds RTC wake stub + data/rodata, including from any source file + named rtc_wake_stub*.c + */ + .rtc.data : + { + *(.rtc.data) + *(.rtc.rodata) + *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*) + } > rtc_slow_seg + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.o(.bss .bss.*) + *rtc_wake_stub*.o(COMMON) + _rtc_bss_end = ABSOLUTE(.); + } > rtc_slow_seg + /* Send .iram0 code to iram */ - .iram0.vectors : + .iram0.vectors : { /* Vectors go to IRAM */ _init_start = ABSOLUTE(.); @@ -47,6 +77,7 @@ SECTIONS _iram_text_start = ABSOLUTE(.); *(.iram1 .iram1.*) *libfreertos.a:(.literal .text .literal.* .text.*) + *libesp32.a:panic.o(.literal .text .literal.* .text.*) *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) *libpp.a:(.literal .text .literal.* .text.*) @@ -92,6 +123,7 @@ SECTIONS KEEP(*(.gnu.linkonce.s2.*)) KEEP(*(.jcr)) *(.dram1 .dram1.*) + *libesp32.a:panic.o(.rodata .rodata.*) _data_end = ABSOLUTE(.); . = ALIGN(4); _heap_start = ABSOLUTE(.); @@ -153,16 +185,4 @@ SECTIONS _text_end = ABSOLUTE(.); _etext = .; } >iram0_2_seg - - .rtc.text : - { - . = ALIGN(4); - *(.rtc.literal .rtc.text) - } >rtc_iram_seg - - .rtc.data : - { - *(.rtc.data) - *(.rtc.rodata) - } > rtc_slow_seg } diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index cc14d3258a..5266a679be 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -286,6 +286,7 @@ PROVIDE ( _global_impure_ptr = 0x3ffae0b0 ); PROVIDE ( gmtime = 0x40059848 ); PROVIDE ( gmtime_r = 0x40059868 ); PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 ); +PROVIDE ( g_rom_flashchip = 0x3ffae270 ); PROVIDE ( gpio_init = 0x40009c20 ); PROVIDE ( gpio_input_get = 0x40009b88 ); PROVIDE ( gpio_input_get_high = 0x40009b9c ); @@ -1584,6 +1585,8 @@ PROVIDE ( SPIEraseBlock = 0x40062c4c ); PROVIDE ( SPIEraseChip = 0x40062c14 ); PROVIDE ( SPIEraseSector = 0x40062ccc ); PROVIDE ( spi_flash_attach = 0x40062a6c ); +/* NB: SPIUnlock @ 0x400628b0 has been replaced with an updated + version in the "spi_flash" component */ PROVIDE ( SPILock = 0x400628f0 ); PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 ); PROVIDE ( spi_modes = 0x3ff99270 ); @@ -1595,9 +1598,8 @@ PROVIDE ( SPIReadModeCnfig = 0x40062944 ); PROVIDE ( SPI_read_status = 0x4006226c ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( SPI_read_status_high = 0x40062448 ); -PROVIDE ( SPIUnlock = 0x400628b0 ); PROVIDE ( SPI_user_command_read = 0x400621b0 ); -PROVIDE ( spi_w25q16 = 0x3ffae270 ); +PROVIDE ( SPI_flashchip_data = 0x3ffae270 ); PROVIDE ( SPIWrite = 0x40062d50 ); /* This is static function, but can be used, not generated by script*/ PROVIDE ( SPI_write_enable = 0x40062320 ); diff --git a/components/esp32/lib b/components/esp32/lib index a1e5f8b953..01f5c068e1 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit a1e5f8b953c7934677ba7a6ed0a6dd2da0e6bd0f +Subproject commit 01f5c068e1ac3968add98439ee2f1748b9e391fa diff --git a/components/freertos/panic.c b/components/esp32/panic.c similarity index 66% rename from components/freertos/panic.c rename to components/esp32/panic.c index 9400867356..c5d8aa669e 100644 --- a/components/freertos/panic.c +++ b/components/esp32/panic.c @@ -25,8 +25,12 @@ #include "soc/io_mux_reg.h" #include "soc/dport_reg.h" #include "soc/rtc_cntl_reg.h" +#include "soc/timer_group_struct.h" +#include "soc/timer_group_reg.h" -#include "gdbstub.h" +#include "esp_gdbstub.h" +#include "esp_panic.h" +#include "esp_attr.h" /* Panic handlers; these get called when an unhandled exception occurs or the assembly-level @@ -34,7 +38,11 @@ task switching / interrupt code runs into an unrecoverable error. The default ta overflow handler also is in here. */ -#if !CONFIG_FREERTOS_PANIC_SILENT_REBOOT +/* +Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled. +*/ + +#if !CONFIG_ESP32_PANIC_SILENT_REBOOT //printf may be broken, so we fix our own printing fns... inline static void panicPutchar(char c) { while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ; @@ -76,7 +84,6 @@ inline static void panicPutHex(int a) { } inline static void panicPutDec(int a) { } #endif -int xPortGetCoreID(); void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) { panicPutStr("***ERROR*** A stack overflow in task "); @@ -105,22 +112,22 @@ void commonErrorHandler(XtExcFrame *frame); static void haltOtherCore() { if (xPortGetCoreID()==0) { //Kill app cpu - CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C1< +#include +#include +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include "esp_err.h" +#include "esp_intr.h" +#include "esp_attr.h" +#include "esp_freertos_hooks.h" +#include "soc/timer_group_struct.h" +#include "soc/timer_group_reg.h" +#include "esp_log.h" + +#include "esp_task_wdt.h" + +#if CONFIG_TASK_WDT + +static const char* TAG = "task_wdt"; + +typedef struct wdt_task_t wdt_task_t; +struct wdt_task_t { + TaskHandle_t task_handle; + bool fed_watchdog; + wdt_task_t *next; +}; + +static wdt_task_t *wdt_task_list=NULL; + +static void IRAM_ATTR task_wdt_isr(void *arg) { + wdt_task_t *wdttask; + const char *cpu; + //Feed the watchdog so we do not reset + TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG0.wdt_feed=1; + TIMERG0.wdt_wprotect=0; + //Ack interrupt + TIMERG0.int_clr_timers.wdt=1; + //Watchdog got triggered because at least one task did not report in. + ets_printf("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n"); + for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) { + if (!wdttask->fed_watchdog) { + cpu=xTaskGetAffinity(wdttask->task_handle)==0?"CPU 0":"CPU 1"; + if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu="CPU 0/1"; + printf(" - %s (%s)\n", pcTaskGetTaskName(wdttask->task_handle), cpu); + } + } + ets_printf("Tasks currently running:\n"); + for (int x=0; xnext) { + //See if we are at the current task. + if (wdttask->task_handle == handle) { + wdttask->fed_watchdog=true; + found_task=true; + } + //If even one task in the list doesn't have the do_feed_wdt var set, we do not feed the watchdog. + if (!wdttask->fed_watchdog) do_feed_wdt=false; + } + + if (!found_task) { + //This is the first time the task calls the task_wdt_feed function. Create a new entry for it in + //the linked list. + wdt_task_t *newtask=malloc(sizeof(wdt_task_t)); + memset(newtask, 0, sizeof(wdt_task_t)); + newtask->task_handle=handle; + newtask->fed_watchdog=true; + if (wdt_task_list == NULL) { + wdt_task_list=newtask; + } else { + for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) ; + wdttask->next=newtask; + } + } + if (do_feed_wdt) { + //All tasks have checked in; time to feed the hw watchdog. + TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG0.wdt_feed=1; + TIMERG0.wdt_wprotect=0; + //Reset fed_watchdog status + for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) wdttask->fed_watchdog=false; + } +} + +void esp_task_wdt_delete() { + TaskHandle_t handle=xTaskGetCurrentTaskHandle(); + wdt_task_t *wdttask=wdt_task_list; + //Wdt task list can't be empty + if (!wdt_task_list) { + ESP_LOGE(TAG, "task_wdt_delete: No tasks in list?"); + return; + } + if (handle==wdt_task_list) { + //Current task is first on list. + wdt_task_list=wdt_task_list->next; + free(wdttask); + } else { + //Find current task in list + while (wdttask->next!=NULL && wdttask->next->task_handle!=handle) wdttask=wdttask->next; + if (!wdttask->next) { + ESP_LOGE(TAG, "task_wdt_delete: Task never called task_wdt_feed!"); + return; + } + wdt_task_t *freeme=wdttask->next; + wdttask->next=wdttask->next->next; + free(freeme); + } +} + + +#if CONFIG_TASK_WDT_CHECK_IDLE_TASK +static bool idle_hook(void) { +#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 + if (xPortGetCoreID()!=0) return true; +#endif + esp_task_wdt_feed(); + return true; +} +#endif + + +void esp_task_wdt_init() { + TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS + TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS + TIMERG0.wdt_config0.level_int_en=1; + TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt + TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system + TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS + TIMERG0.wdt_config2=CONFIG_TASK_WDT_TIMEOUT_S*2000; //Set timeout before interrupt + TIMERG0.wdt_config3=CONFIG_TASK_WDT_TIMEOUT_S*4000; //Set timeout before reset + TIMERG0.wdt_config0.en=1; + TIMERG0.wdt_feed=1; + TIMERG0.wdt_wprotect=0; +#if CONFIG_TASK_WDT_CHECK_IDLE_TASK + esp_register_freertos_idle_hook(idle_hook); +#endif + ESP_INTR_DISABLE(ETS_T0_WDT_INUM); + intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM); + xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL); + TIMERG0.int_clr_timers.wdt=1; + TIMERG0.int_ena.wdt=1; + ESP_INTR_ENABLE(ETS_T0_WDT_INUM); +} + + +#endif \ No newline at end of file diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index 3da802296a..8bab51225e 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -94,4 +94,31 @@ config ESPTOOLPY_FLASHFREQ default "26m" if ESPTOOLPY_FLASHFREQ_26M default "20m" if ESPTOOLPY_FLASHFREQ_20M + +choice ESPTOOLPY_FLASHSIZE + prompt "Flash size" + default ESPTOOLPY_FLASHSIZE_2MB + help + SPI flash size, in megabytes + +config ESPTOOLPY_FLASHSIZE_1MB + bool "1 MB" +config ESPTOOLPY_FLASHSIZE_2MB + bool "2 MB" +config ESPTOOLPY_FLASHSIZE_4MB + bool "4 MB" +config ESPTOOLPY_FLASHSIZE_8MB + bool "8 MB" +config ESPTOOLPY_FLASHSIZE_16MB + bool "16 MB" +endchoice + +config ESPTOOLPY_FLASHSIZE + string + default "1MB" if ESPTOOLPY_FLASHSIZE_1MB + default "2MB" if ESPTOOLPY_FLASHSIZE_2MB + default "4MB" if ESPTOOLPY_FLASHSIZE_4MB + default "8MB" if ESPTOOLPY_FLASHSIZE_8MB + default "16MB" if ESPTOOLPY_FLASHSIZE_16MB + endmenu diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index 4d0dd1b3e5..aa3bb2bfa9 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -4,31 +4,54 @@ ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT) ESPBAUD ?= $(CONFIG_ESPTOOLPY_BAUD) ESPFLASHMODE ?= $(CONFIG_ESPTOOLPY_FLASHMODE) ESPFLASHFREQ ?= $(CONFIG_ESPTOOLPY_FLASHFREQ) +ESPFLASHSIZE ?= $(CONFIG_ESPTOOLPY_FLASHSIZE) PYTHON ?= $(call dequote,$(CONFIG_PYTHON)) # two commands that can be used from other components # to invoke esptool.py (with or without serial port args) # -# NB: esptool.py lives in the sdk/bin directory not the component directory ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32 ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD) -# the no-stub argument is temporary until esptool.py fully supports compressed uploads -ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) +# Supporting esptool command line tools +ESPEFUSEPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espefuse.py +ESPSECUREPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espsecure.py +export ESPSECUREPY # is used in bootloader_support component + +ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE) + +ESPTOOL_ELF2IMAGE_OPTIONS := + +ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS) ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) -$(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC) - $(Q) $(ESPTOOLPY) elf2image --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) -o $@ $< +ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +ifndef IS_BOOTLOADER_BUILD +# for secure boot, add a signing step to get from unsiged app to signed app +APP_BIN_UNSIGNED := $(APP_BIN:.bin=-unsigned.bin) + +$(APP_BIN): $(APP_BIN_UNSIGNED) + $(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $^ # signed in-place +endif +endif +# non-secure boot (or bootloader), both these files are the same +APP_BIN_UNSIGNED ?= $(APP_BIN) + +$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) + $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $< flash: all_binaries $(ESPTOOLPY_SRC) @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..." - $(Q) $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) +ifdef CONFIG_SECURE_BOOTLOADER_ENABLED + @echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)" +endif + $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) @echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..." - $(Q) $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) + $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) $(eval $(call SubmoduleCheck,$(ESPTOOLPY_SRC),$(COMPONENT_PATH)/esptool)) diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index 197ba605fe..b1e00025fa 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit 197ba605fe0c05e16bf4c5ec07b726adc8d86abc +Subproject commit b1e00025fa6cbc63062b205259ee70d91bfe4989 diff --git a/components/expat/component.mk b/components/expat/component.mk index 907b358a87..0ee1199d1b 100644 --- a/components/expat/component.mk +++ b/components/expat/component.mk @@ -1,15 +1,9 @@ # # Component Makefile # -# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, -# this will take the sources in this directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the SDK documents if you need to do this. -# COMPONENT_ADD_INCLUDEDIRS := port/include include/expat COMPONENT_SRCDIRS := library port CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H -include $(IDF_PATH)/make/component_common.mk diff --git a/components/freertos/FreeRTOS-openocd.c b/components/freertos/FreeRTOS-openocd.c index 6177f02057..d74564495e 100644 --- a/components/freertos/FreeRTOS-openocd.c +++ b/components/freertos/FreeRTOS-openocd.c @@ -18,6 +18,6 @@ #define USED #endif -#ifdef CONFIG_FREERTOS_DEBUG_OCDAWARE +#ifdef CONFIG_ESP32_DEBUG_OCDAWARE const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1; #endif \ No newline at end of file diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 1a65e1eeb7..b9db00e50b 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -93,45 +93,6 @@ config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS If using the WiFi stack, this value must be at least 1. -#This still needs to be implemented. -choice FREERTOS_PANIC - prompt "Panic handler behaviour" - default FREERTOS_PANIC_PRINT_REBOOT - help - If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is - invoked. Configure the panic handlers action here. - -config FREERTOS_PANIC_PRINT_HALT - bool "Print registers and halt" - help - Outputs the relevant registers over the serial port and halt the - processor. Needs a manual reset to restart. - -config FREERTOS_PANIC_PRINT_REBOOT - bool "Print registers and reboot" - help - Outputs the relevant registers over the serial port and immediately - reset the processor. - -config FREERTOS_PANIC_SILENT_REBOOT - bool "Silent reboot" - help - Just resets the processor without outputting anything - -config FREERTOS_PANIC_GDBSTUB - bool "Invoke GDBStub" - help - Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem - of the crash. -endchoice - -config FREERTOS_DEBUG_OCDAWARE - bool "Make exception and panic handlers JTAG/OCD aware" - default y - help - The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and - instead of panicking, have the debugger stop on the offending instruction. - choice FREERTOS_ASSERT prompt "FreeRTOS assertions" default FREERTOS_ASSERT_FAIL_ABORT @@ -160,7 +121,7 @@ endchoice config FREERTOS_BREAK_ON_SCHEDULER_START_JTAG bool "Stop program on scheduler start when JTAG/OCD is detected" - depends on FREERTOS_DEBUG_OCDAWARE + depends on ESP32_DEBUG_OCDAWARE default y help If JTAG/OCD is connected, stop execution when the scheduler is started and the first @@ -172,6 +133,43 @@ menuconfig ENABLE_MEMORY_DEBUG help Enable this option to show malloc heap block and memory crash detect +config FREERTOS_ISR_STACKSIZE + int "ISR stack size" + range 1536 32768 + default 1536 + help + The interrupt handlers have their own stack. The size of the stack can be defined here. + Each processor has its own stack, so the total size occupied will be twice this. + +config FREERTOS_LEGACY_HOOKS + bool "Use FreeRTOS legacy hooks" + default n + help + FreeRTOS offers a number of hooks/callback functions that are called when a timer + tick happens, the idle thread runs etc. esp-idf replaces these by runtime registerable + hooks using the esp_register_freertos_xxx_hook system, but for legacy reasons the old + hooks can also still be enabled. Please enable this only if you have code that for some + reason can't be migrated to the esp_register_freertos_xxx_hook system. + +if FREERTOS_LEGACY_HOOKS + +config FREERTOS_LEGACY_IDLE_HOOK + bool "Enable legacy idle hook" + default n + help + If enabled, FreeRTOS will call a function called vApplicationIdleHook when the idle thread + on a CPU is running. Please make sure your code defines such a function. + +config FREERTOS_LEGACY_TICK_HOOK + bool "Enable legacy tick hook" + default n + help + If enabled, FreeRTOS will call a function called vApplicationTickHook when a FreeRTOS + tick is executed. Please make sure your code defines such a function. + +endif #FREERTOS_LEGACY_HOOKS + + menuconfig FREERTOS_DEBUG_INTERNALS bool "Debug FreeRTOS internals" default n @@ -197,6 +195,8 @@ config FREERTOS_PORTMUX_DEBUG_RECURSIVE If enabled, additional debug information will be printed for recursive portMUX usage. + + endif # FREERTOS_DEBUG_INTERNALS endmenu diff --git a/components/freertos/component.mk b/components/freertos/component.mk index 6702d1b95c..0240ea235f 100644 --- a/components/freertos/component.mk +++ b/components/freertos/component.mk @@ -6,4 +6,3 @@ COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) -Wl,--undefined=uxTopUsedPriority COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := include/freertos -include $(IDF_PATH)/make/component_common.mk diff --git a/components/freertos/include/freertos/FreeRTOS.h b/components/freertos/include/freertos/FreeRTOS.h index 04b39b65e9..f6c9aa497d 100644 --- a/components/freertos/include/freertos/FreeRTOS.h +++ b/components/freertos/include/freertos/FreeRTOS.h @@ -74,6 +74,7 @@ * Include the generic headers required for the FreeRTOS port being used. */ #include +#include "sys/reent.h" /* * If stdint.h cannot be located then: @@ -739,6 +740,20 @@ extern "C" { #define portTICK_TYPE_IS_ATOMIC 0 #endif +#ifndef configSUPPORT_STATIC_ALLOCATION + /* Defaults to 0 for backward compatibility. */ + #define configSUPPORT_STATIC_ALLOCATION 0 +#endif + +#ifndef configSUPPORT_DYNAMIC_ALLOCATION + /* Defaults to 1 for backward compatibility. */ + #define configSUPPORT_DYNAMIC_ALLOCATION 1 +#endif + +#if( ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) ) + #error configSUPPORT_STATIC_ALLOCATION and configSUPPORT_DYNAMIC_ALLOCATION cannot both be 0, but can both be 1. +#endif + #if( portTICK_TYPE_IS_ATOMIC == 0 ) /* Either variables of tick type cannot be read atomically, or portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when @@ -791,6 +806,153 @@ V8 if desired. */ #define configESP32_PER_TASK_DATA 1 #endif +/* + * In line with software engineering best practice, FreeRTOS implements a strict + * data hiding policy, so the real structures used by FreeRTOS to maintain the + * state of tasks, queues, semaphores, etc. are not accessible to the application + * code. However, if the application writer wants to statically allocate such + * an object then the size of the object needs to be know. Dummy structures + * that are guaranteed to have the same size and alignment requirements of the + * real objects are used for this purpose. The dummy list and list item + * structures below are used for inclusion in such a dummy structure. + */ +struct xSTATIC_LIST_ITEM +{ + TickType_t xDummy1; + void *pvDummy2[ 4 ]; +}; +typedef struct xSTATIC_LIST_ITEM StaticListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +struct xSTATIC_MINI_LIST_ITEM +{ + TickType_t xDummy1; + void *pvDummy2[ 2 ]; +}; +typedef struct xSTATIC_MINI_LIST_ITEM StaticMiniListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +typedef struct xSTATIC_LIST +{ + UBaseType_t uxDummy1; + void *pvDummy2; + StaticMiniListItem_t xDummy3; +} StaticList_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Task structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a task then + * the size of the task object needs to be know. The StaticTask_t structure + * below is provided for this purpose. Its sizes and alignment requirements are + * guaranteed to match those of the genuine structure, no matter which + * architecture is being used, and no matter how the values in FreeRTOSConfig.h + * are set. Its contents are somewhat obfuscated in the hope users will + * recognise that it would be unwise to make direct use of the structure members. + */ +typedef struct xSTATIC_TCB +{ + void *pxDummy1; + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xDummy2; + #endif + StaticListItem_t xDummy3[ 2 ]; + UBaseType_t uxDummy5; + void *pxDummy6; + uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; + UBaseType_t uxDummyCoreId; + #if ( portSTACK_GROWTH > 0 ) + void *pxDummy8; + #endif + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxDummy9; + uint32_t OldInterruptState; + #endif + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy10[ 2 ]; + #endif + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxDummy12[ 2 ]; + #endif + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + void *pxDummy14; + #endif + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) + void *pvDummyLocalStorageCallBack[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + #endif + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulDummy16; + #endif + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + struct _reent xDummy17; + #endif + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + uint32_t ulDummy18; + uint32_t ucDummy19; + #endif + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t uxDummy20; + #endif + +} StaticTask_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Queue structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a queue + * then the size of the queue object needs to be know. The StaticQueue_t + * structure below is provided for this purpose. Its sizes and alignment + * requirements are guaranteed to match those of the genuine structure, no + * matter which architecture is being used, and no matter how the values in + * FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in the hope + * users will recognise that it would be unwise to make direct use of the + * structure members. + */ +typedef struct xSTATIC_QUEUE +{ + void *pvDummy1[ 3 ]; + + union + { + void *pvDummy2; + UBaseType_t uxDummy2; + } u; + + StaticList_t xDummy3[ 2 ]; + UBaseType_t uxDummy4[ 3 ]; + BaseType_t ucDummy5[ 2 ]; + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy6; + #endif + + #if ( configUSE_QUEUE_SETS == 1 ) + void *pvDummy7; + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy8; + uint8_t ucDummy9; + #endif + + struct { + volatile uint32_t mux; + #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG + const char *lastLockedFn; + int lastLockedLine; + #endif + } mux; + +} StaticQueue_t; +typedef StaticQueue_t StaticSemaphore_t; + #ifdef __cplusplus } #endif diff --git a/components/freertos/include/freertos/FreeRTOSConfig.h b/components/freertos/include/freertos/FreeRTOSConfig.h index d1958e7701..13ce73e0a8 100644 --- a/components/freertos/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/include/freertos/FreeRTOSConfig.h @@ -152,9 +152,9 @@ *----------------------------------------------------------*/ #define configUSE_PREEMPTION 1 -#define configUSE_IDLE_HOOK 0 +#define configUSE_IDLE_HOOK ( CONFIG_FREERTOS_LEGACY_IDLE_HOOK ) -#define configUSE_TICK_HOOK 0 +#define configUSE_TICK_HOOK ( CONFIG_FREERTOS_LEGACY_TICK_HOOK ) #define configTICK_RATE_HZ ( CONFIG_FREERTOS_HZ ) @@ -180,7 +180,7 @@ /* The Xtensa port uses a separate interrupt stack. Adjust the stack size */ /* to suit the needs of your specific application. */ #ifndef configISR_STACK_SIZE -#define configISR_STACK_SIZE 1024//2048 +#define configISR_STACK_SIZE CONFIG_FREERTOS_ISR_STACKSIZE #endif /* Minimal heap size to make sure examples can run on memory limited @@ -231,6 +231,7 @@ #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_pcTaskGetTaskName 1 #if CONFIG_ENABLE_MEMORY_DEBUG #define configENABLE_MEMORY_DEBUG 1 @@ -251,6 +252,8 @@ #define configUSE_NEWLIB_REENTRANT 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 + /* Test FreeRTOS timers (with timer task) and more. */ /* Some files don't compile if this flag is disabled */ #define configUSE_TIMERS 1 @@ -262,12 +265,6 @@ #define INCLUDE_eTaskGetState 1 #define configUSE_QUEUE_SETS 1 -#if (!defined XT_INTEXC_HOOKS) -#define configXT_INTEXC_HOOKS 1 /* Exception hooks used by certain tests */ -#if configUSE_TRACE_FACILITY_2 -#define configASSERT_2 1 /* Specific to Xtensa port */ -#endif -#endif #define configXT_BOARD 1 /* Board mode */ #define configXT_SIMULATOR 0 diff --git a/components/freertos/include/freertos/panic.h b/components/freertos/include/freertos/panic.h deleted file mode 100644 index 9e902ed20b..0000000000 --- a/components/freertos/include/freertos/panic.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef PANIC_H -#define PANIC_H - -void setBreakpointIfJtag(void *fn); - - -#endif \ No newline at end of file diff --git a/components/freertos/include/freertos/portable.h b/components/freertos/include/freertos/portable.h index 4030ca0c03..9ed378a8ab 100644 --- a/components/freertos/include/freertos/portable.h +++ b/components/freertos/include/freertos/portable.h @@ -179,6 +179,14 @@ BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION; */ void vPortEndScheduler( void ) PRIVILEGED_FUNCTION; + +/* + * Send an interrupt to another core in order to make the task running + * on it yield for a higher-priority task. + */ + +void vPortYieldOtherCore( BaseType_t coreid) PRIVILEGED_FUNCTION; + /* * The structures and methods of manipulating the MPU are contained within the * port layer. @@ -192,8 +200,14 @@ void vPortEndScheduler( void ) PRIVILEGED_FUNCTION; #endif /* Multi-core: get current core ID */ -int xPortGetCoreID( void ); - +static inline uint32_t xPortGetCoreID() { + int id; + asm volatile( + "rsr.prid %0\n" + " extui %0,%0,13,1" + :"=r"(id)); + return id; +} #ifdef __cplusplus } diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index ab83b0e05a..f20a4a1e26 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -225,6 +225,26 @@ static inline unsigned portENTER_CRITICAL_NESTED() { unsigned state = XTOS_SET_I #define portCLEAR_INTERRUPT_MASK_FROM_ISR(state) portEXIT_CRITICAL_NESTED(state) +/* + * Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare + * *mux to compare, and if it's the same, will set *mux to set. It will return the old value + * of *addr in *set. + * + * Warning: From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the + * *bitwise inverse* of the old mem if the mem wasn't written. This doesn't seem to happen on the + * ESP32, though. (Would show up directly if it did because the magic wouldn't match.) + */ +static inline void uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set) { + __asm__ __volatile__( + "WSR %2,SCOMPARE1 \n" + "ISYNC \n" + "S32C1I %0, %1, 0 \n" + :"=r"(*set) + :"r"(addr), "r"(compare), "0"(*set) + ); +} + + /*-----------------------------------------------------------*/ /* Architecture specifics. */ diff --git a/components/freertos/include/freertos/queue.h b/components/freertos/include/freertos/queue.h index 2095c59b0c..876f1a1b30 100644 --- a/components/freertos/include/freertos/queue.h +++ b/components/freertos/include/freertos/queue.h @@ -170,7 +170,95 @@ typedef void * QueueSetMemberHandle_t; * \defgroup xQueueCreate xQueueCreate * \ingroup QueueManagement */ -#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( uxQueueLength, uxItemSize, queueQUEUE_TYPE_BASE ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) +#endif + +/** + * queue. h + *
+ QueueHandle_t xQueueCreateStatic(
+							  UBaseType_t uxQueueLength,
+							  UBaseType_t uxItemSize,
+							  uint8_t *pucQueueStorageBuffer,
+							  StaticQueue_t *pxQueueBuffer
+						  );
+ * 
+ * + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @param pucQueueStorageBuffer If uxItemSize is not zero then + * pucQueueStorageBuffer must point to a uint8_t array that is at least large + * enough to hold the maximum number of items that can be in the queue at any + * one time - which is ( uxQueueLength * uxItemsSize ) bytes. If uxItemSize is + * zero then pucQueueStorageBuffer can be NULL. + * + * @param pxQueueBuffer Must point to a variable of type StaticQueue_t, which + * will be used to hold the queue's data structure. + * + * @return If the queue is created then a handle to the created queue is + * returned. If pxQueueBuffer is NULL then NULL is returned. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ };
+
+ #define QUEUE_LENGTH 10
+ #define ITEM_SIZE sizeof( uint32_t )
+
+ // xQueueBuffer will hold the queue structure.
+ StaticQueue_t xQueueBuffer;
+
+ // ucQueueStorage will hold the items posted to the queue.  Must be at least
+ // [(queue length) * ( queue item size)] bytes long.
+ uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ];
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( QUEUE_LENGTH, // The number of items the queue can hold.
+							ITEM_SIZE	  // The size of each item in the queue
+							&( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue.
+							&xQueueBuffer ); // The buffer that will hold the queue structure.
+
+	// The queue is guaranteed to be created successfully as no dynamic memory
+	// allocation is used.  Therefore xQueue1 is now a handle to a valid queue.
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueCreateStatic xQueueCreateStatic + * \ingroup QueueManagement + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer ) xQueueGenericCreateStatic( ( uxQueueLength ), ( uxItemSize ), ( pucQueueStorage ), ( pxQueueBuffer ), ( queueQUEUE_TYPE_BASE ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * queue. h @@ -1479,7 +1567,9 @@ BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTi * these functions directly. */ QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; /* @@ -1538,10 +1628,22 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION #endif /* - * Generic version of the queue creation function, which is in turn called by - * any queue, semaphore or mutex creation function or macro. + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. */ -QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#endif /* * Queue sets provide a mechanism to allow a task to block (pend) on a read diff --git a/components/freertos/include/freertos/ringbuf.h b/components/freertos/include/freertos/ringbuf.h index 7884e9856e..93ba30758e 100644 --- a/components/freertos/include/freertos/ringbuf.h +++ b/components/freertos/include/freertos/ringbuf.h @@ -18,22 +18,34 @@ to this bit of memory will block. The requirement for items to be contiguous is slightly problematic when the only way to place the next item would involve a wraparound from the end to the beginning of the ringbuffer. This can -be solved in two ways: -- allow_split_items = pdTRUE: The insertion code will split the item in two items; one which fits +be solved (or not) in a few ways: +- type = RINGBUF_TYPE_ALLOWSPLIT: The insertion code will split the item in two items; one which fits in the space left at the end of the ringbuffer, one that contains the remaining data which is placed in the beginning. Two xRingbufferReceive calls will be needed to retrieve the data. -- allow_split_items = pdFALSE: The insertion code will leave the room at the end of the ringbuffer +- type = RINGBUF_TYPE_NOSPLIT: The insertion code will leave the room at the end of the ringbuffer unused and instead will put the entire item at the start of the ringbuffer, as soon as there is enough free space. +- type = RINGBUF_TYPE_BYTEBUF: This is your conventional byte-based ringbuffer. It does have no +overhead, but it has no item contiguousness either: a read will just give you the entire written +buffer space, or the space up to the end of the buffer, and writes can be broken up in any way +possible. Note that this type cannot do a 2nd read before returning the memory of the 1st. The maximum size of an item will be affected by this decision. When split items are allowed, it's acceptable to push items of (buffer_size)-16 bytes into the buffer. When it's not allowed, the -maximum size is (buffer_size/2)-8 bytes. +maximum size is (buffer_size/2)-8 bytes. The bytebuf can fill the entire buffer with data, it has +no overhead. */ //An opaque handle for a ringbuff object. typedef void * RingbufHandle_t; +//The various types of buffer +typedef enum { + RINGBUF_TYPE_NOSPLIT = 0, + RINGBUF_TYPE_ALLOWSPLIT, + RINGBUF_TYPE_BYTEBUF +} ringbuf_type_t; + /** * @brief Create a ring buffer @@ -45,7 +57,7 @@ typedef void * RingbufHandle_t; * * @return A RingbufHandle_t handle to the created ringbuffer, or NULL in case of error. */ -RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_items); +RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type); /** @@ -120,6 +132,34 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size); +/** + * @brief Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes + * to return + * + * @param ringbuf - Ring buffer to retrieve the item from + * @param item_size - Pointer to a variable to which the size of the retrieved item will be written. + * @param xTicksToWait - Ticks to wait for items in the ringbuffer. + * + * @return Pointer to the retrieved item on success; *item_size filled with the length of the + * item. NULL on timeout, *item_size is untouched in that case. + */ +void *xRingbufferReceiveUpTo(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait, size_t wanted_size); + + +/** + * @brief Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes + * to return. Call this from an ISR. + * + * @param ringbuf - Ring buffer to retrieve the item from + * @param item_size - Pointer to a variable to which the size of the retrieved item will be written. + * + * @return Pointer to the retrieved item on success; *item_size filled with the length of the + * item. NULL when the ringbuffer is empty, *item_size is untouched in that case. + */ +void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size, size_t wanted_size); + + + /** * @brief Return a previously-retrieved item to the ringbuffer * diff --git a/components/freertos/include/freertos/semphr.h b/components/freertos/include/freertos/semphr.h index 5866ab1ec5..6343d0190a 100644 --- a/components/freertos/include/freertos/semphr.h +++ b/components/freertos/include/freertos/semphr.h @@ -128,19 +128,37 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary * \ingroup Semaphores */ -#define vSemaphoreCreateBinary( xSemaphore ) \ - { \ - ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ - if( ( xSemaphore ) != NULL ) \ - { \ - ( void ) xSemaphoreGive( ( xSemaphore ) ); \ - } \ - } +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define vSemaphoreCreateBinary( xSemaphore ) \ + { \ + ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ + if( ( xSemaphore ) != NULL ) \ + { \ + ( void ) xSemaphoreGive( ( xSemaphore ) ); \ + } \ + } +#endif /** * semphr. h *
SemaphoreHandle_t xSemaphoreCreateBinary( void )
* + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this * xSemaphoreCreateBinary() function. Note that binary semaphores created using * the vSemaphoreCreateBinary() macro are created in a state such that the @@ -182,7 +200,68 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary * \ingroup Semaphores */ -#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * NOTE: In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the semaphore is created then a handle to the created semaphore is + * returned. If pxSemaphoreBuffer is NULL then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+ StaticSemaphore_t xSemaphoreBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateBinary().
+    // The semaphore's data structures will be placed in the xSemaphoreBuffer
+    // variable, the address of which is passed into the function.  The
+    // function's parameter is not NULL, so the function will not attempt any
+    // dynamic memory allocation, and therefore the function will not return
+    // return NULL.
+    xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer );
+
+    // Rest of task code goes here.
+ }
+ 
+ * \defgroup xSemaphoreCreateBinaryStatic xSemaphoreCreateBinaryStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h @@ -652,9 +731,18 @@ typedef QueueHandle_t SemaphoreHandle_t; * Macro that implements a mutex semaphore by using the existing queue * mechanism. * - * Mutexes created using this macro can be accessed using the xSemaphoreTake() + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and - * xSemaphoreGiveRecursive() macros should not be used. + * xSemaphoreGiveRecursive() macros must not be used. * * This type of semaphore uses a priority inheritance mechanism so a task * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the @@ -667,8 +755,9 @@ typedef QueueHandle_t SemaphoreHandle_t; * semaphore and another always 'takes' the semaphore) and from within interrupt * service routines. * - * @return xSemaphore Handle to the created mutex semaphore. Should be of type - * SemaphoreHandle_t. + * @return If the mutex was successfully created then a handle to the created + * semaphore is returned. If there was not enough heap to allocate the mutex + * data structures then NULL is returned. * * Example usage:
@@ -690,19 +779,93 @@ typedef QueueHandle_t SemaphoreHandle_t;
  * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
  * \ingroup Semaphores
  */
-#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
+#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
+	#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
+#endif
+
+/**
+ * semphr. h
+ * 
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros must not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will be used to hold the mutex's data structure, removing the need for + * the memory to be allocated dynamically. + * + * @return If the mutex was successfully created then a handle to the created + * mutex is returned. If pxMutexBuffer was NULL then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xMutexBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // A mutex cannot be used before it has been created.  xMutexBuffer is
+    // into xSemaphoreCreateMutexStatic() so no dynamic memory allocation is
+    // attempted.
+    xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
+
+    // As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
+    // so there is no need to check it.
+ }
+ 
+ * \defgroup xSemaphoreCreateMutexStatic xSemaphoreCreateMutexStatic + * \ingroup Semaphores + */ + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
* - * Macro that implements a recursive mutex by using the existing queue - * mechanism. + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. * * Mutexes created using this macro can be accessed using the * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The - * xSemaphoreTake() and xSemaphoreGive() macros should not be used. + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. * * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex * doesn't become available again until the owner has called @@ -745,14 +908,104 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex * \ingroup Semaphores */ -#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) +#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) + #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the recursive mutex's data structure, + * removing the need for the memory to be allocated dynamically. + * + * @return If the recursive mutex was successfully created then a handle to the + * created recursive mutex is returned. If pxMutexBuffer was NULL then NULL is + * returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xMutexBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // A recursive semaphore cannot be used before it is created.  Here a
+    // recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic().
+    // The address of xMutexBuffer is passed into the function, and will hold
+    // the mutexes data structures - so no dynamic memory allocation will be
+    // attempted.
+    xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );
+
+    // As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
+    // so there is no need to check it.
+ }
+ 
+ * \defgroup xSemaphoreCreateRecursiveMutexStatic xSemaphoreCreateRecursiveMutexStatic + * \ingroup Semaphores + */ +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) + #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h *
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
* - * Macro that creates a counting semaphore by using the existing - * queue mechanism. + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer can + * instead optionally provide the memory that will get used by the counting + * semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting + * semaphore to be created without using any dynamic memory allocation. * * Counting semaphores are typically used for two things: * @@ -808,7 +1061,94 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting * \ingroup Semaphores */ -#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer must + * provide the memory. xSemaphoreCreateCountingStatic() therefore allows a + * counting semaphore to be created without using any dynamic memory allocation. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the counting semaphore was successfully created then a handle to + * the created counting semaphore is returned. If pxSemaphoreBuffer was NULL + * then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xSemaphoreBuffer;
+
+ void vATask( void * pvParameters )
+ {
+ SemaphoreHandle_t xSemaphore = NULL;
+
+    // Counting semaphore cannot be used before they have been created.  Create
+    // a counting semaphore using xSemaphoreCreateCountingStatic().  The max
+    // value to which the semaphore can count is 10, and the initial value
+    // assigned to the count will be 0.  The address of xSemaphoreBuffer is
+    // passed in and will be used to hold the semaphore structure, so no dynamic
+    // memory allocation will be used.
+    xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer );
+
+    // No memory allocation was attempted so xSemaphore cannot be NULL, so there
+    // is no need to check its value.
+ }
+ 
+ * \defgroup xSemaphoreCreateCountingStatic xSemaphoreCreateCountingStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h diff --git a/components/freertos/include/freertos/task.h b/components/freertos/include/freertos/task.h index 9f3f3d659e..f7b9181fcf 100644 --- a/components/freertos/include/freertos/task.h +++ b/components/freertos/include/freertos/task.h @@ -177,6 +177,7 @@ typedef struct xTASK_STATUS UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */ UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ + StackType_t *pxStackBase; /* Points to the lowest address of the task's stack area. */ uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ } TaskStatus_t; @@ -281,8 +282,19 @@ is used in assert() statements. */ );
* * Create a new task and add it to the list of tasks that are ready to run. - * On multicore environments, this will give no specific affinity to the task. - * Use xTaskCreatePinnedToCore to give affinity. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * See xTaskCreateStatic() for a version that does not use any dynamic memory + * allocation. * * xTaskCreate() can only be used to create a task that has unrestricted * access to the entire microcontroller memory map. Systems that include MPU @@ -350,8 +362,139 @@ is used in assert() statements. */ * \defgroup xTaskCreate xTaskCreate * \ingroup Tasks */ -#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ), tskNO_AFFINITY ) -#define xTaskCreatePinnedToCore( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ), xCoreID ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + const BaseType_t xCoreID); + +#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskCreatePinnedToCore( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), tskNO_AFFINITY ) +#endif + +/** + * task. h + *
+ TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode,
+								 const char * const pcName,
+								 uint32_t ulStackDepth,
+								 void *pvParameters,
+								 UBaseType_t uxPriority,
+								 StackType_t *pxStackBuffer,
+								 StaticTask_t *pxTaskBuffer,
+                                 const BaseType_t xCoreID );
+ + * + * Create a new task and add it to the list of tasks that are ready to run. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. The maximum length of the string is defined by + * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. + * + * @param ulStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 32-bits wide and ulStackDepth is defined as 100 then 400 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task will run. + * + * @param pxStackBuffer Must point to a StackType_t array that has at least + * ulStackDepth indexes - the array will then be used as the task's stack, + * removing the need for the stack to be allocated dynamically. + * + * @param pxTaskBuffer Must point to a variable of type StaticTask_t, which will + * then be used to hold the task's data structures, removing the need for the + * memory to be allocated dynamically. + * + * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will + * be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer + * are NULL then the task will not be created and + * errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned. + * + * Example usage: +
+
+    // Dimensions the buffer that the task being created will use as its stack.
+    // NOTE:  This is the number of words the stack will hold, not the number of
+    // bytes.  For example, if each stack item is 32-bits, and this is set to 100,
+    // then 400 bytes (100 * 32-bits) will be allocated.
+    #define STACK_SIZE 200
+
+    // Structure that will hold the TCB of the task being created.
+    StaticTask_t xTaskBuffer;
+
+    // Buffer that the task being created will use as its stack.  Note this is
+    // an array of StackType_t variables.  The size of StackType_t is dependent on
+    // the RTOS port.
+    StackType_t xStack[ STACK_SIZE ];
+
+    // Function that implements the task being created.
+    void vTaskCode( void * pvParameters )
+    {
+        // The parameter value is expected to be 1 as 1 is passed in the
+        // pvParameters value in the call to xTaskCreateStatic().
+        configASSERT( ( uint32_t ) pvParameters == 1UL );
+
+        for( ;; )
+        {
+            // Task code goes here.
+        }
+    }
+
+    // Function that creates a task.
+    void vOtherFunction( void )
+    {
+        TaskHandle_t xHandle = NULL;
+
+        // Create the task without using any dynamic memory allocation.
+        xHandle = xTaskCreateStatic(
+                      vTaskCode,       // Function that implements the task.
+                      "NAME",          // Text name for the task.
+                      STACK_SIZE,      // Stack size in words, not bytes.
+                      ( void * ) 1,    // Parameter passed into the task.
+                      tskIDLE_PRIORITY,// Priority at which the task is created.
+                      xStack,          // Array to use as the task's stack.
+                      &xTaskBuffer );  // Variable to hold the task's data structure.
+
+        // puxStackBuffer and pxTaskBuffer were not NULL, so the task will have
+        // been created, and xHandle will be the task's handle.  Use the handle
+        // to suspend the task.
+        vTaskSuspend( xHandle );
+    }
+   
+ * \defgroup xTaskCreateStatic xTaskCreateStatic + * \ingroup Tasks + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer, + const BaseType_t xCoreID ); + +#define xTaskCreateStatic( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxStackBuffer, pxTaskBuffer ) xTaskCreateStaticPinnedToCore( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxStackBuffer ), ( pxTaskBuffer ), tskNO_AFFINITY ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * task. h @@ -420,7 +563,9 @@ TaskHandle_t xHandle; * \defgroup xTaskCreateRestricted xTaskCreateRestricted * \ingroup Tasks */ -#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) ) +#if( portUSING_MPU_WRAPPERS == 1 ) + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif /** * task. h @@ -1933,6 +2078,17 @@ TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION; */ TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION; + + +/* + * Return the handle of the task running on a certain CPU. Because of + * the nature of SMP processing, there is no guarantee that this + * value will still be valid on return and should only be used for + * debugging purposes. + */ +TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t cpuid ); + + /* * Capture the current time status for future reference. */ @@ -1968,12 +2124,6 @@ void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTIO */ BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; -/* - * Generic version of the task creation function which is in turn called by the - * xTaskCreate() and xTaskCreateRestricted() macros. - */ -BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions, const BaseType_t xCoreID) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - /* * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. */ diff --git a/components/freertos/include/freertos/xtensa_api.h b/components/freertos/include/freertos/xtensa_api.h index 04ad7d62d8..87922691dd 100644 --- a/components/freertos/include/freertos/xtensa_api.h +++ b/components/freertos/include/freertos/xtensa_api.h @@ -42,7 +42,8 @@ typedef void (*xt_exc_handler)(XtExcFrame *); /* ------------------------------------------------------------------------------- - Call this function to set a handler for the specified exception. + Call this function to set a handler for the specified exception. The handler + will be installed on the core that calls this function. n - Exception number (type) f - Handler function address, NULL to uninstall handler. @@ -61,7 +62,8 @@ extern xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f); /* ------------------------------------------------------------------------------- - Call this function to set a handler for the specified interrupt. + Call this function to set a handler for the specified interrupt. The handler + will be installed on the core that calls this function. n - Interrupt number. f - Handler function address, NULL to uninstall handler. @@ -73,7 +75,8 @@ extern xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg); /* ------------------------------------------------------------------------------- - Call this function to enable the specified interrupts. + Call this function to enable the specified interrupts on the core that runs + this code. mask - Bit mask of interrupts to be enabled. ------------------------------------------------------------------------------- @@ -83,7 +86,8 @@ extern void xt_ints_on(unsigned int mask); /* ------------------------------------------------------------------------------- - Call this function to disable the specified interrupts. + Call this function to disable the specified interrupts on the core that runs + this code. mask - Bit mask of interrupts to be disabled. ------------------------------------------------------------------------------- diff --git a/components/freertos/include/freertos/xtensa_context.h b/components/freertos/include/freertos/xtensa_context.h index 3167c84726..b748a0d1a7 100644 --- a/components/freertos/include/freertos/xtensa_context.h +++ b/components/freertos/include/freertos/xtensa_context.h @@ -322,12 +322,7 @@ STRUCT_END(XtSolFrame) #ifdef __ASSEMBLER__ .macro getcoreid reg rsr.prid \reg - bbci \reg,1,1f - movi \reg,1 - j 2f -1: - movi \reg,0 -2: + extui \reg,\reg,13,1 .endm #endif diff --git a/components/freertos/port.c b/components/freertos/port.c index 6117a2804e..25480ed475 100644 --- a/components/freertos/port.c +++ b/components/freertos/port.c @@ -101,7 +101,9 @@ #include "FreeRTOS.h" #include "task.h" -#include "panic.h" +#include "esp_panic.h" + +#include "esp_crosscore_int.h" /* Defined in portasm.h */ extern void _frxt_tick_timer_init(void); @@ -228,6 +230,12 @@ BaseType_t xPortSysTickHandler( void ) return ret; } + + +void vPortYieldOtherCore( BaseType_t coreid ) { + esp_crosscore_int_send_yield( coreid ); +} + /*-----------------------------------------------------------*/ /* @@ -253,28 +261,6 @@ void vPortAssertIfInISR() configASSERT(port_interruptNesting[xPortGetCoreID()]==0) } - -/* - * Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare - * *mux to compare, and if it's the same, will set *mux to set. It will return the old value - * of *addr. - * - * Warning: From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the - * *bitwise inverse* of the old mem if the mem wasn't written. This doesn't seem to happen on the - * ESP32, though. (Would show up directly if it did because the magic wouldn't match.) - */ -uint32_t uxPortCompareSet(volatile uint32_t *mux, uint32_t compare, uint32_t set) -{ - __asm__ __volatile__ ( - "WSR %2,SCOMPARE1 \n" //initialize SCOMPARE1 - "ISYNC \n" //wait sync - "S32C1I %0, %1, 0 \n" //store id into the lock, if the lock is the same as comparel. Otherwise, no write-access - :"=r"(set) \ - :"r"(mux), "r"(compare), "0"(set) \ - ); - return set; -} - /* * For kernel use: Initialize a per-CPU mux. Mux will be initialized unlocked. */ @@ -310,7 +296,8 @@ void vPortCPUAcquireMutex(portMUX_TYPE *mux) { irqStatus=portENTER_CRITICAL_NESTED(); do { //Lock mux if it's currently unlocked - res=uxPortCompareSet(&mux->mux, portMUX_FREE_VAL, (xPortGetCoreID()<mux, portMUX_FREE_VAL, &res); //If it wasn't free and we're the owner of the lock, we are locking recursively. if ( (res != portMUX_FREE_VAL) && (((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT) == xPortGetCoreID()) ) { //Mux was already locked by us. Just bump the recurse count by one. @@ -362,29 +349,33 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) { if ( (mux->mux & portMUX_MAGIC_MASK) != portMUX_MAGIC_VAL ) ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is uninitialized (0x%X)!\n", mux, mux->mux); #endif //Unlock mux if it's currently locked with a recurse count of 0 - res=uxPortCompareSet(&mux->mux, (xPortGetCoreID()<mux, (xPortGetCoreID()<>portMUX_VAL_SHIFT) == xPortGetCoreID() ) { + //Lock is valid, we can return safely. Just need to check if it's a recursive lock; if so we need to decrease the refcount. + if ( ((res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT)!=0) { + //We locked this, but the reccount isn't zero. Decrease refcount and continue. + recCnt=(res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT; + recCnt--; +#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE + ets_printf("Recursive unlock: recCnt=%d last locked %s line %d, curr %s line %d\n", recCnt, lastLockedFn, lastLockedLine, fnName, line); +#endif + mux->mux=portMUX_MAGIC_VAL|(recCnt<>portMUX_VAL_SHIFT) != xPortGetCoreID() ) { + } else { #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG ets_printf("ERROR: vPortCPUReleaseMutex: mux %p wasn't locked by this core (%d) but by core %d (ret=%x, mux=%x).\n", mux, xPortGetCoreID(), ((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT), res, mux->mux); ets_printf("Last non-recursive lock %s line %d\n", lastLockedFn, lastLockedLine); ets_printf("Called by %s line %d\n", fnName, line); #endif ret=pdFALSE; - } else if ( ((res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT)!=0) { - //We locked this, but the reccount isn't zero. Decrease refcount and continue. - recCnt=(res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT; - recCnt--; -#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE - ets_printf("Recursive unlock: recCnt=%d last locked %s line %d, curr %s line %d\n", recCnt, lastLockedFn, lastLockedLine, fnName, line); -#endif - mux->mux=portMUX_MAGIC_VAL|(recCnt<pxTopOfStack = SP */ movi a1, port_IntStackTop /* a1 = top of intr stack */ movi a2, configISR_STACK_SIZE - getcoreid a3 - mull a2, a3, a2 + mull a2, a4, a2 add a1, a1, a2 /* for current proc */ .Lnested: @@ -177,12 +162,11 @@ _frxt_int_enter: .align 4 _frxt_int_exit: - getcoreid a3 - slli a4, a3, 2 /* a4 is core * 4 */ + getcoreid a4 movi a2, port_xSchedulerRunning - add a2, a2, a4 + addx4 a2, a4, a2 movi a3, port_interruptNesting - add a3, a3, a4 + addx4 a3, a4, a3 rsil a0, XCHAL_EXCM_LEVEL /* lock out interrupts */ l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */ beqz a2, .Lnoswitch /* scheduler not running, no tasks */ @@ -192,13 +176,13 @@ _frxt_int_exit: bnez a2, .Lnesting /* !=0 after decr so still nested */ movi a2, pxCurrentTCB - add a2, a2, a4 + addx4 a2, a4, a2 l32i a2, a2, 0 /* a2 = current TCB */ beqz a2, 1f /* no task ? go to dispatcher */ l32i a1, a2, TOPOFSTACK_OFFS /* SP = pxCurrentTCB->pxTopOfStack */ movi a2, port_switch_flag /* address of switch flag */ - add a2, a2, a4 /* point to flag for this cpu */ + addx4 a2, a4, a2 /* point to flag for this cpu */ l32i a3, a2, 0 /* a3 = port_switch_flag */ beqz a3, .Lnoswitch /* flag = 0 means no switch reqd */ movi a3, 0 @@ -404,14 +388,12 @@ _frxt_dispatch: call0 vTaskSwitchContext // Get next TCB to resume movi a2, pxCurrentTCB getcoreid a3 - slli a3, a3, 2 - add a2, a2, a3 + addx4 a2, a3, a2 #else call4 vTaskSwitchContext // Get next TCB to resume movi a2, pxCurrentTCB getcoreid a3 - slli a3, a3, 2 - add a2, a2, a3 + addx4 a2, a3, a2 #endif l32i a3, a2, 0 l32i sp, a3, TOPOFSTACK_OFFS /* SP = next_TCB->pxTopOfStack; */ @@ -451,8 +433,7 @@ _frxt_dispatch: /* Restore CPENABLE from task's co-processor save area. */ movi a3, pxCurrentTCB /* cp_state = */ getcoreid a2 - slli a2, a2, 2 - add a3, a2, a3 + addx4 a3, a2, a3 l32i a3, a3, 0 l32i a2, a3, CP_TOPOFSTACK_OFFS /* StackType_t *pxStack; */ l16ui a3, a2, XT_CPENABLE /* CPENABLE = cp_state->cpenable; */ @@ -541,8 +522,7 @@ vPortYield: movi a2, pxCurrentTCB getcoreid a3 - slli a3, a3, 2 - add a2, a2, a3 + addx4 a2, a3, a2 l32i a2, a2, 0 /* a2 = pxCurrentTCB */ movi a3, 0 s32i a3, sp, XT_SOL_EXIT /* 0 to flag as solicited frame */ @@ -593,8 +573,7 @@ vPortYieldFromInt: /* Save CPENABLE in task's co-processor save area, and clear CPENABLE. */ movi a3, pxCurrentTCB /* cp_state = */ getcoreid a2 - slli a2, a2, 2 - add a3, a2, a3 + addx4 a3, a2, a3 l32i a3, a3, 0 l32i a2, a3, CP_TOPOFSTACK_OFFS @@ -637,18 +616,17 @@ _frxt_task_coproc_state: /* We can use a3 as a scratchpad, the instances of code calling XT_RTOS_CP_STATE don't seem to need it saved. */ getcoreid a3 - slli a3, a3, 2 /* a3=coreid*4 */ movi a15, port_xSchedulerRunning /* if (port_xSchedulerRunning */ - add a15, a15, a3 + addx4 a15, a3,a15 l32i a15, a15, 0 beqz a15, 1f movi a15, port_interruptNesting /* && port_interruptNesting == 0 */ - add a15, a15, a3 + addx4 a15, a3, a15 l32i a15, a15, 0 bnez a15, 1f movi a15, pxCurrentTCB - add a15, a3, a15 + addx4 a15, a3, a15 l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */ diff --git a/components/freertos/queue.c b/components/freertos/queue.c index 168f09f1a1..f404a243e6 100644 --- a/components/freertos/queue.c +++ b/components/freertos/queue.c @@ -158,15 +158,19 @@ typedef struct QueueDefinition UBaseType_t uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ UBaseType_t uxItemSize; /*< The size of each items that the queue will hold. */ - #if ( configUSE_TRACE_FACILITY == 1 ) - UBaseType_t uxQueueNumber; - uint8_t ucQueueType; + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */ #endif #if ( configUSE_QUEUE_SETS == 1 ) struct QueueDefinition *pxQueueSetContainer; #endif + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxQueueNumber; + uint8_t ucQueueType; + #endif + portMUX_TYPE mux; } xQUEUE; @@ -238,6 +242,21 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; #endif +/* + * Called after a Queue_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; + +/* + * Mutexes are a special type of queue. When a mutex is created, first the + * queue is created, then prvInitialiseMutex() is called to configure the queue + * as a mutex. + */ +#if( configUSE_MUTEXES == 1 ) + static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; +#endif + BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) { Queue_t * const pxQueue = ( Queue_t * ) xQueue; @@ -293,132 +312,165 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; } /*-----------------------------------------------------------*/ -QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) -{ -Queue_t *pxNewQueue; -size_t xQueueSizeInBytes; -QueueHandle_t xReturn = NULL; -int8_t *pcAllocatedBuffer; +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + + configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); + + /* The StaticQueue_t structure and the queue storage area must be + supplied. */ + configASSERT( pxStaticQueue != NULL ); + + /* A queue storage area should be provided if the item size is not 0, and + should not be provided if the item size is 0. */ + configASSERT( !( ( pucQueueStorage != NULL ) && ( uxItemSize == 0 ) ) ); + configASSERT( !( ( pucQueueStorage == NULL ) && ( uxItemSize != 0 ) ) ); + + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticQueue_t or StaticSemaphore_t equals the size of + the real queue and semaphore structures. */ + volatile size_t xSize = sizeof( StaticQueue_t ); + configASSERT( xSize == sizeof( Queue_t ) ); + } + #endif /* configASSERT_DEFINED */ + + /* The address of a statically allocated queue was passed in, use it. + The address of a statically allocated storage area was also passed in + but is already set. */ + pxNewQueue = ( Queue_t * ) pxStaticQueue; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + + if( pxNewQueue != NULL ) + { + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Queues can be allocated wither statically or dynamically, so + note this queue was allocated statically in case the queue is + later deleted. */ + pxNewQueue->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); + } + + return pxNewQueue; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + size_t xQueueSizeInBytes; + uint8_t *pucQueueStorage; + + configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); + + if( uxItemSize == ( UBaseType_t ) 0 ) + { + /* There is not going to be a queue storage area. */ + xQueueSizeInBytes = ( size_t ) 0; + } + else + { + /* Allocate enough space to hold the maximum number of items that + can be in the queue at any time. */ + xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + + pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); + + if( pxNewQueue != NULL ) + { + /* Jump past the queue structure to find the location of the queue + storage area. */ + pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Queues can be created either statically or dynamically, so + note this task was created dynamically in case it is later + deleted. */ + pxNewQueue->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); + } + + return pxNewQueue; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) +{ /* Remove compiler warnings about unused parameters should configUSE_TRACE_FACILITY not be set to 1. */ ( void ) ucQueueType; - configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); - if( uxItemSize == ( UBaseType_t ) 0 ) { - /* There is not going to be a queue storage area. */ - xQueueSizeInBytes = ( size_t ) 0; + /* No RAM was allocated for the queue storage area, but PC head cannot + be set to NULL because NULL is used as a key to say the queue is used as + a mutex. Therefore just set pcHead to point to the queue as a benign + value that is known to be within the memory map. */ + pxNewQueue->pcHead = ( int8_t * ) pxNewQueue; } else { - /* The queue is one byte longer than asked for to make wrap checking - easier/faster. */ - xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + /* Set the head to the start of the queue storage area. */ + pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage; } - /* Allocate the new queue structure and storage area. */ - pcAllocatedBuffer = ( int8_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); + /* Initialise the queue members as described where the queue type is + defined. */ + pxNewQueue->uxLength = uxQueueLength; + pxNewQueue->uxItemSize = uxItemSize; + ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); - if( pcAllocatedBuffer != NULL ) + #if ( configUSE_TRACE_FACILITY == 1 ) { - pxNewQueue = ( Queue_t * ) pcAllocatedBuffer; /*lint !e826 MISRA The buffer cannot be to small because it was dimensioned by sizeof( Queue_t ) + xQueueSizeInBytes. */ - - if( uxItemSize == ( UBaseType_t ) 0 ) - { - /* No RAM was allocated for the queue storage area, but PC head - cannot be set to NULL because NULL is used as a key to say the queue - is used as a mutex. Therefore just set pcHead to point to the queue - as a benign value that is known to be within the memory map. */ - pxNewQueue->pcHead = ( int8_t * ) pxNewQueue; - } - else - { - /* Jump past the queue structure to find the location of the queue - storage area - adding the padding bytes to get a better alignment. */ - pxNewQueue->pcHead = pcAllocatedBuffer + sizeof( Queue_t ); - } - - /* Initialise the queue members as described above where the queue type - is defined. */ - pxNewQueue->uxLength = uxQueueLength; - pxNewQueue->uxItemSize = uxItemSize; - ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); - - #if ( configUSE_TRACE_FACILITY == 1 ) - { - pxNewQueue->ucQueueType = ucQueueType; - } - #endif /* configUSE_TRACE_FACILITY */ - - #if( configUSE_QUEUE_SETS == 1 ) - { - pxNewQueue->pxQueueSetContainer = NULL; - } - #endif /* configUSE_QUEUE_SETS */ - - traceQUEUE_CREATE( pxNewQueue ); - xReturn = pxNewQueue; + pxNewQueue->ucQueueType = ucQueueType; } - else + #endif /* configUSE_TRACE_FACILITY */ + + #if( configUSE_QUEUE_SETS == 1 ) { - mtCOVERAGE_TEST_MARKER(); + pxNewQueue->pxQueueSetContainer = NULL; } + #endif /* configUSE_QUEUE_SETS */ - configASSERT( xReturn ); - - return xReturn; + traceQUEUE_CREATE( pxNewQueue ); } /*-----------------------------------------------------------*/ -#if ( configUSE_MUTEXES == 1 ) +#if( configUSE_MUTEXES == 1 ) - QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) + static void prvInitialiseMutex( Queue_t *pxNewQueue ) { - Queue_t *pxNewQueue; - - /* Prevent compiler warnings about unused parameters if - configUSE_TRACE_FACILITY does not equal 1. */ - ( void ) ucQueueType; - - /* Allocate the new queue structure. */ - pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) ); if( pxNewQueue != NULL ) { - /* Information required for priority inheritance. */ + /* The queue create function will set all the queue structure members + correctly for a generic queue, but this function is creating a + mutex. Overwrite those members that need to be set differently - + in particular the information required for priority inheritance. */ pxNewQueue->pxMutexHolder = NULL; pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; - /* Queues used as a mutex no data is actually copied into or out - of the queue. */ - pxNewQueue->pcWriteTo = NULL; - pxNewQueue->u.pcReadFrom = NULL; + /* In case this is a recursive mutex. */ + pxNewQueue->u.uxRecursiveCallCount = 0; - /* Each mutex has a length of 1 (like a binary semaphore) and - an item size of 0 as nothing is actually copied into or out - of the mutex. */ - pxNewQueue->uxMessagesWaiting = ( UBaseType_t ) 0U; - pxNewQueue->uxLength = ( UBaseType_t ) 1U; - pxNewQueue->uxItemSize = ( UBaseType_t ) 0U; - - #if ( configUSE_TRACE_FACILITY == 1 ) - { - pxNewQueue->ucQueueType = ucQueueType; - } - #endif - - #if ( configUSE_QUEUE_SETS == 1 ) - { - pxNewQueue->pxQueueSetContainer = NULL; - } - #endif - - /* Ensure the event queues start with the correct state. */ - vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) ); - vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); - - vPortCPUInitializeMutex(&pxNewQueue->mux); + vPortCPUInitializeMutex(&pxNewQueue->mux); traceCREATE_MUTEX( pxNewQueue ); @@ -429,8 +481,41 @@ int8_t *pcAllocatedBuffer; { traceCREATE_MUTEX_FAILED(); } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; + + pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); + prvInitialiseMutex( pxNewQueue ); + + return pxNewQueue; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) + { + Queue_t *pxNewQueue; + const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; + + /* Prevent compiler warnings about unused parameters if + configUSE_TRACE_FACILITY does not equal 1. */ + ( void ) ucQueueType; + + pxNewQueue = ( Queue_t * ) xQueueGenericCreateStatic( uxMutexLength, uxMutexSize, NULL, pxStaticQueue, ucQueueType ); + prvInitialiseMutex( pxNewQueue ); - configASSERT( pxNewQueue ); return pxNewQueue; } @@ -565,7 +650,35 @@ int8_t *pcAllocatedBuffer; #endif /* configUSE_RECURSIVE_MUTEXES */ /*-----------------------------------------------------------*/ -#if ( configUSE_COUNTING_SEMAPHORES == 1 ) +#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) + { + QueueHandle_t xHandle; + + configASSERT( uxMaxCount != 0 ); + configASSERT( uxInitialCount <= uxMaxCount ); + + xHandle = xQueueGenericCreateStatic( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); + + if( xHandle != NULL ) + { + ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; + + traceCREATE_COUNTING_SEMAPHORE(); + } + else + { + traceCREATE_COUNTING_SEMAPHORE_FAILED(); + } + + return xHandle; + } + +#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) { @@ -591,7 +704,7 @@ int8_t *pcAllocatedBuffer; return xHandle; } -#endif /* configUSE_COUNTING_SEMAPHORES */ +#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ /*-----------------------------------------------------------*/ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) @@ -1685,7 +1798,33 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; vQueueUnregisterQueue( pxQueue ); } #endif - vPortFree( pxQueue ); + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The queue can only have been allocated dynamically - free it + again. */ + vPortFree( pxQueue ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The queue could have been allocated statically or dynamically, so + check before attempting to free the memory. */ + if( pxQueue->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxQueue ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #else + { + /* The queue must have been statically allocated, so is not going to be + deleted. Avoid compiler warnings about the unused parameter. */ + ( void ) pxQueue; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ } /*-----------------------------------------------------------*/ @@ -2263,7 +2402,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; #endif /* configUSE_TIMERS */ /*-----------------------------------------------------------*/ -#if ( configUSE_QUEUE_SETS == 1 ) +#if( ( configUSE_QUEUE_SETS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength ) { diff --git a/components/freertos/readme_smp.txt b/components/freertos/readme_smp.txt index 38f332416a..fdd9b146b1 100644 --- a/components/freertos/readme_smp.txt +++ b/components/freertos/readme_smp.txt @@ -19,11 +19,6 @@ it would on a single-core system: the other core still will keep on executing all it's own. Use a mux, queue or semaphore to protect your structures instead. -- While each core has individual interrupts, the handlers are shared. This -means that when you set a handler for an interrupt, it will get triggered if -the interrupt is triggered on both CPU0 as well as on CPU1. This is something -we may change in future FreeRTOS-esp32 releases. - - This FreeRTOS version has the task local storage backported from the 8.2.x versions. It, however, has an addition: you can also set a callback when you set the pointer. This callback will be called by the idle task, with the diff --git a/components/freertos/ringbuf.c b/components/freertos/ringbuf.c index 6045c5a695..a4205d88dc 100644 --- a/components/freertos/ringbuf.c +++ b/components/freertos/ringbuf.c @@ -18,6 +18,7 @@ #include "freertos/queue.h" #include "freertos/xtensa_api.h" #include "freertos/ringbuf.h" +#include "esp_attr.h" #include #include #include @@ -25,6 +26,7 @@ typedef enum { flag_allowsplit = 1, + flag_bytebuf = 2, } rbflag_t; typedef enum { @@ -33,8 +35,10 @@ typedef enum { } itemflag_t; +typedef struct ringbuf_t ringbuf_t; + //The ringbuffer structure -typedef struct { +struct ringbuf_t { SemaphoreHandle_t free_space_sem; //Binary semaphore, wakes up writing threads when there's more free space SemaphoreHandle_t items_buffered_sem; //Binary semaphore, indicates there are new packets in the circular buffer. See remark. size_t size; //Size of the data storage @@ -44,7 +48,12 @@ typedef struct { uint8_t *data; //Data storage portMUX_TYPE mux; //Spinlock for actual data/ptr/struct modification rbflag_t flags; -} ringbuf_t; + size_t maxItemSize; + //The following keep function pointers to hold different implementations for ringbuffer management. + BaseType_t (*copyItemToRingbufImpl)(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size); + uint8_t *(*getItemFromRingbufImpl)(ringbuf_t *rb, size_t *length, int wanted_length); + void (*returnItemToRingbufImpl)(ringbuf_t *rb, void *item); +}; @@ -73,14 +82,16 @@ static int ringbufferFreeMem(ringbuf_t *rb) return free_size-1; } -//Copies a single item to the ring buffer. Assumes there is space in the ringbuffer and + +//Copies a single item to the ring buffer; refuses to split items. Assumes there is space in the ringbuffer and //the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on //success, pdFALSE if it can't make the item fit and the calling routine needs to retry //later or fail. //This function by itself is not threadsafe, always call from within a muxed section. -static BaseType_t copyItemToRingbuf(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) +static BaseType_t copyItemToRingbufNoSplit(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) { - size_t rbuffer_size=(buffer_size+3)&~3; //Payload length, rounded to next 32-bit value + size_t rbuffer_size; + rbuffer_size=(buffer_size+3)&~3; //Payload length, rounded to next 32-bit value configASSERT(((int)rb->write_ptr&3)==0); //write_ptr needs to be 32-bit aligned configASSERT(rb->write_ptr-(rb->data+rb->size) >= sizeof(buf_entry_hdr_t)); //need to have at least the size //of a header to the end of the ringbuff @@ -88,65 +99,28 @@ static BaseType_t copyItemToRingbuf(ringbuf_t *rb, uint8_t *buffer, size_t buffe //See if we have enough contiguous space to write the buffer. if (rem_len < rbuffer_size + sizeof(buf_entry_hdr_t)) { - //The buffer can't be contiguously written to the ringbuffer, but needs special handling. Do - //that depending on how the ringbuffer is configured. - //The code here is also expected to check if the buffer, mangled in whatever way is implemented, - //will still fit, and return pdFALSE if that is not the case. - if (rb->flags & flag_allowsplit) { - //Buffer plus header is not going to fit in the room from wr_pos to the end of the - //ringbuffer... we need to split the write in two. - //First, see if this will fit at all. - if (ringbufferFreeMem(rb) < (sizeof(buf_entry_hdr_t)*2)+rbuffer_size) { - //Will not fit. - return pdFALSE; - } - //Because the code at the end of the function makes sure we always have - //room for a header, this should never assert. - configASSERT(rem_len>=sizeof(buf_entry_hdr_t)); - //Okay, it should fit. Write everything. - //First, place bit of buffer that does fit. Write header first... - buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr; - hdr->flags=0; - hdr->len=rem_len-sizeof(buf_entry_hdr_t); - rb->write_ptr+=sizeof(buf_entry_hdr_t); - rem_len-=sizeof(buf_entry_hdr_t); - if (rem_len!=0) { - //..then write the data bit that fits. - memcpy(rb->write_ptr, buffer, rem_len); - //Update vars so the code later on will write the rest of the data. - buffer+=rem_len; - rbuffer_size-=rem_len; - buffer_size-=rem_len; - } else { - //Huh, only the header fit. Mark as dummy so the receive function doesn't receive - //an useless zero-byte packet. - hdr->flags|=iflag_dummydata; - } - rb->write_ptr=rb->data; - } else { - //Buffer plus header is not going to fit in the room from wr_pos to the end of the - //ringbuffer... but we're not allowed to split the buffer. We need to fill the - //rest of the ringbuffer with a dummy item so we can place the data at the _start_ of - //the ringbuffer.. - //First, find out if we actually have enough space at the start of the ringbuffer to - //make this work (Again, we need 4 bytes extra because otherwise read_ptr==free_ptr) - if (rb->free_ptr-rb->data < rbuffer_size+sizeof(buf_entry_hdr_t)+4) { - //Will not fit. - return pdFALSE; - } - //If the read buffer hasn't wrapped around yet, there's no way this will work either. - if (rb->free_ptr > rb->write_ptr) { - //No luck. - return pdFALSE; - } - - //Okay, it will fit. Mark the rest of the ringbuffer space with a dummy packet. - buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr; - hdr->flags=iflag_dummydata; - //Reset the write pointer to the start of the ringbuffer so the code later on can - //happily write the data. - rb->write_ptr=rb->data; + //Buffer plus header is not going to fit in the room from wr_pos to the end of the + //ringbuffer... but we're not allowed to split the buffer. We need to fill the + //rest of the ringbuffer with a dummy item so we can place the data at the _start_ of + //the ringbuffer.. + //First, find out if we actually have enough space at the start of the ringbuffer to + //make this work (Again, we need 4 bytes extra because otherwise read_ptr==free_ptr) + if (rb->free_ptr-rb->data < rbuffer_size+sizeof(buf_entry_hdr_t)+4) { + //Will not fit. + return pdFALSE; } + //If the read buffer hasn't wrapped around yet, there's no way this will work either. + if (rb->free_ptr > rb->write_ptr) { + //No luck. + return pdFALSE; + } + + //Okay, it will fit. Mark the rest of the ringbuffer space with a dummy packet. + buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr; + hdr->flags=iflag_dummydata; + //Reset the write pointer to the start of the ringbuffer so the code later on can + //happily write the data. + rb->write_ptr=rb->data; } else { //No special handling needed. Checking if it's gonna fit probably still is a good idea. if (ringbufferFreeMem(rb) < sizeof(buf_entry_hdr_t)+rbuffer_size) { @@ -174,9 +148,117 @@ static BaseType_t copyItemToRingbuf(ringbuf_t *rb, uint8_t *buffer, size_t buffe return pdTRUE; } +//Copies a single item to the ring buffer; allows split items. Assumes there is space in the ringbuffer and +//the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on +//success, pdFALSE if it can't make the item fit and the calling routine needs to retry +//later or fail. +//This function by itself is not threadsafe, always call from within a muxed section. +static BaseType_t copyItemToRingbufAllowSplit(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) +{ + size_t rbuffer_size; + rbuffer_size=(buffer_size+3)&~3; //Payload length, rounded to next 32-bit value + configASSERT(((int)rb->write_ptr&3)==0); //write_ptr needs to be 32-bit aligned + configASSERT(rb->write_ptr-(rb->data+rb->size) >= sizeof(buf_entry_hdr_t)); //need to have at least the size + //of a header to the end of the ringbuff + size_t rem_len=(rb->data + rb->size) - rb->write_ptr; //length remaining until end of ringbuffer + + //See if we have enough contiguous space to write the buffer. + if (rem_len < rbuffer_size + sizeof(buf_entry_hdr_t)) { + //The buffer can't be contiguously written to the ringbuffer, but needs special handling. Do + //that depending on how the ringbuffer is configured. + //The code here is also expected to check if the buffer, mangled in whatever way is implemented, + //will still fit, and return pdFALSE if that is not the case. + //Buffer plus header is not going to fit in the room from wr_pos to the end of the + //ringbuffer... we need to split the write in two. + //First, see if this will fit at all. + if (ringbufferFreeMem(rb) < (sizeof(buf_entry_hdr_t)*2)+rbuffer_size) { + //Will not fit. + return pdFALSE; + } + //Because the code at the end of the function makes sure we always have + //room for a header, this should never assert. + configASSERT(rem_len>=sizeof(buf_entry_hdr_t)); + //Okay, it should fit. Write everything. + //First, place bit of buffer that does fit. Write header first... + buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr; + hdr->flags=0; + hdr->len=rem_len-sizeof(buf_entry_hdr_t); + rb->write_ptr+=sizeof(buf_entry_hdr_t); + rem_len-=sizeof(buf_entry_hdr_t); + if (rem_len!=0) { + //..then write the data bit that fits. + memcpy(rb->write_ptr, buffer, rem_len); + //Update vars so the code later on will write the rest of the data. + buffer+=rem_len; + rbuffer_size-=rem_len; + buffer_size-=rem_len; + } else { + //Huh, only the header fit. Mark as dummy so the receive function doesn't receive + //an useless zero-byte packet. + hdr->flags|=iflag_dummydata; + } + rb->write_ptr=rb->data; + } else { + //No special handling needed. Checking if it's gonna fit probably still is a good idea. + if (ringbufferFreeMem(rb) < sizeof(buf_entry_hdr_t)+rbuffer_size) { + //Buffer is not going to fit, period. + return pdFALSE; + } + } + + //If we are here, the buffer is guaranteed to fit in the space starting at the write pointer. + buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr; + hdr->len=buffer_size; + hdr->flags=0; + rb->write_ptr+=sizeof(buf_entry_hdr_t); + memcpy(rb->write_ptr, buffer, buffer_size); + rb->write_ptr+=rbuffer_size; + + //The buffer will wrap around if we don't have room for a header anymore. + if ((rb->data+rb->size)-rb->write_ptr < sizeof(buf_entry_hdr_t)) { + //'Forward' the write buffer until we are at the start of the ringbuffer. + //The read pointer will always be at the start of a full header, which cannot + //exist at the point of the current write pointer, so there's no chance of overtaking + //that. + rb->write_ptr=rb->data; + } + return pdTRUE; +} + + +//Copies a bunch of daya to the ring bytebuffer. Assumes there is space in the ringbuffer and +//the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on +//success, pdFALSE if it can't make the item fit and the calling routine needs to retry +//later or fail. +//This function by itself is not threadsafe, always call from within a muxed section. +static BaseType_t copyItemToRingbufByteBuf(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) +{ + size_t rem_len=(rb->data + rb->size) - rb->write_ptr; //length remaining until end of ringbuffer + + //See if we have enough contiguous space to write the buffer. + if (rem_len < buffer_size) { + //...Nope. Write the data bit that fits. + memcpy(rb->write_ptr, buffer, rem_len); + //Update vars so the code later on will write the rest of the data. + buffer+=rem_len; + buffer_size-=rem_len; + rb->write_ptr=rb->data; + } + + //If we are here, the buffer is guaranteed to fit in the space starting at the write pointer. + memcpy(rb->write_ptr, buffer, buffer_size); + rb->write_ptr+=buffer_size; + //The buffer will wrap around if we're at the end. + if ((rb->data+rb->size)==rb->write_ptr) { + rb->write_ptr=rb->data; + } + return pdTRUE; +} + //Retrieves a pointer to the data of the next item, or NULL if this is not possible. //This function by itself is not threadsafe, always call from within a muxed section. -static uint8_t *getItemFromRingbuf(ringbuf_t *rb, size_t *length) +//Because we always return one item, this function ignores the wanted_length variable. +static uint8_t *getItemFromRingbufDefault(ringbuf_t *rb, size_t *length, int wanted_length) { uint8_t *ret; configASSERT(((int)rb->read_ptr&3)==0); @@ -210,10 +292,48 @@ static uint8_t *getItemFromRingbuf(ringbuf_t *rb, size_t *length) return ret; } +//Retrieves a pointer to the data in the buffer, or NULL if this is not possible. +//This function by itself is not threadsafe, always call from within a muxed section. +//This function honours the wanted_length and will never return more data than this. +static uint8_t *getItemFromRingbufByteBuf(ringbuf_t *rb, size_t *length, int wanted_length) +{ + uint8_t *ret; + if (rb->read_ptr != rb->free_ptr) { + //This type of ringbuff does not support multiple outstanding buffers. + return NULL; + } + if (rb->read_ptr == rb->write_ptr) { + //No data available. + return NULL; + } + ret=rb->read_ptr; + if (rb->read_ptr > rb->write_ptr) { + //Available data wraps around. Give data until the end of the buffer. + *length=rb->size-(rb->read_ptr - rb->data); + if (wanted_length != 0 && *length > wanted_length) { + *length=wanted_length; + rb->read_ptr+=wanted_length; + } else { + rb->read_ptr=rb->data; + } + } else { + //Return data up to write pointer. + *length=rb->write_ptr -rb->read_ptr; + if (wanted_length != 0 && *length > wanted_length) { + *length=wanted_length; + rb->read_ptr+=wanted_length; + } else { + rb->read_ptr=rb->write_ptr; + } + } + return ret; +} + + //Returns an item to the ringbuffer. Will mark the item as free, and will see if the free pointer //can be increase. //This function by itself is not threadsafe, always call from within a muxed section. -static void returnItemToRingbuf(ringbuf_t *rb, void *item) { +static void returnItemToRingbufDefault(ringbuf_t *rb, void *item) { uint8_t *data=(uint8_t*)item; configASSERT(((int)rb->free_ptr&3)==0); configASSERT(data >= rb->data); @@ -243,12 +363,26 @@ static void returnItemToRingbuf(ringbuf_t *rb, void *item) { if ((rb->data+rb->size)-rb->free_ptr < sizeof(buf_entry_hdr_t)) { rb->free_ptr=rb->data; } + //The free_ptr can not exceed read_ptr, otherwise write_ptr might overwrite read_ptr. + //Read_ptr can not set to rb->data with free_ptr, otherwise write_ptr might wrap around to rb->data. + if(rb->free_ptr == rb->read_ptr) break; //Next header hdr=(buf_entry_hdr_t *)rb->free_ptr; } } +//Returns an item to the ringbuffer. Will mark the item as free, and will see if the free pointer +//can be increase. +//This function by itself is not threadsafe, always call from within a muxed section. +static void returnItemToRingbufBytebuf(ringbuf_t *rb, void *item) { + uint8_t *data=(uint8_t*)item; + configASSERT(data >= rb->data); + configASSERT(data < rb->data+rb->size); + //Free the read memory. + rb->free_ptr=rb->read_ptr; +} + void xRingbufferPrintInfo(RingbufHandle_t ringbuf) { ringbuf_t *rb=(ringbuf_t *)ringbuf; @@ -259,7 +393,7 @@ void xRingbufferPrintInfo(RingbufHandle_t ringbuf) -RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_items) +RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type) { ringbuf_t *rb = malloc(sizeof(ringbuf_t)); if (rb==NULL) goto err; @@ -273,9 +407,35 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_item rb->free_space_sem = xSemaphoreCreateBinary(); rb->items_buffered_sem = xSemaphoreCreateBinary(); rb->flags=0; - if (allow_split_items) rb->flags|=flag_allowsplit; + if (type==RINGBUF_TYPE_ALLOWSPLIT) { + rb->flags|=flag_allowsplit; + rb->copyItemToRingbufImpl=copyItemToRingbufAllowSplit; + rb->getItemFromRingbufImpl=getItemFromRingbufDefault; + rb->returnItemToRingbufImpl=returnItemToRingbufDefault; + //Calculate max item size. Worst case, we need to split an item into two, which means two headers of overhead. + rb->maxItemSize=rb->size-(sizeof(buf_entry_hdr_t)*2)-4; + } else if (type==RINGBUF_TYPE_BYTEBUF) { + rb->flags|=flag_bytebuf; + rb->copyItemToRingbufImpl=copyItemToRingbufByteBuf; + rb->getItemFromRingbufImpl=getItemFromRingbufByteBuf; + rb->returnItemToRingbufImpl=returnItemToRingbufBytebuf; + //Calculate max item size. We have no headers and can split anywhere -> size is total size minus one. + rb->maxItemSize=rb->size-1; + } else if (type==RINGBUF_TYPE_NOSPLIT) { + rb->copyItemToRingbufImpl=copyItemToRingbufNoSplit; + rb->getItemFromRingbufImpl=getItemFromRingbufDefault; + rb->returnItemToRingbufImpl=returnItemToRingbufDefault; + //Calculate max item size. Worst case, we have the write ptr in such a position that we are lacking four bytes of free + //memory to put an item into the rest of the memory. If this happens, we have to dummy-fill + //(item_data-4) bytes of buffer, then we only have (size-(item_data-4) bytes left to fill + //with the real item. (item size being header+data) + rb->maxItemSize=(rb->size/2)-sizeof(buf_entry_hdr_t)-4; + } else { + configASSERT(0); + } if (rb->free_space_sem == NULL || rb->items_buffered_sem == NULL) goto err; vPortCPUInitializeMutex(&rb->mux); + return (RingbufHandle_t)rb; err: @@ -303,18 +463,7 @@ size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf) { ringbuf_t *rb=(ringbuf_t *)ringbuf; configASSERT(rb); - //In both cases, we return 4 bytes less than what we actually can have. If the ringbuffer is - //indeed entirely filled, read_ptr==free_ptr, which throws off the free space calculation. - if (rb->flags & flag_allowsplit) { - //Worst case, we need to split an item into two, which means two headers of overhead. - return rb->size-(sizeof(buf_entry_hdr_t)*2)-4; - } else { - //Worst case, we have the write ptr in such a position that we are lacking four bytes of free - //memory to put an item into the rest of the memory. If this happens, we have to dummy-fill - //(item_data-4) bytes of buffer, then we only have (size-(item_data-4) bytes left to fill - //with the real item. (item size being header+data) - return (rb->size/2)-sizeof(buf_entry_hdr_t)-4; - } + return rb->maxItemSize; } BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, TickType_t ticks_to_wait) @@ -352,7 +501,7 @@ BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, portENTER_CRITICAL(&rb->mux); //Another thread may have been able to sneak its write first. Check again now we locked the ringbuff, and retry //everything if this is the case. Otherwise, we can write and are done. - done=copyItemToRingbuf(rb, data, dataSize); + done=rb->copyItemToRingbufImpl(rb, data, dataSize); portEXIT_CRITICAL(&rb->mux); } xSemaphoreGive(rb->items_buffered_sem); @@ -371,8 +520,7 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t da //Does not fit in the remaining space in the ringbuffer. write_succeeded=pdFALSE; } else { - copyItemToRingbuf(rb, data, dataSize); - write_succeeded=pdTRUE; + write_succeeded = rb->copyItemToRingbufImpl(rb, data, dataSize); } portEXIT_CRITICAL_ISR(&rb->mux); if (write_succeeded) { @@ -382,7 +530,7 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t da } -void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait) +static void *xRingbufferReceiveGeneric(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait, size_t wanted_size) { ringbuf_t *rb=(ringbuf_t *)ringbuf; uint8_t *itemData; @@ -399,7 +547,7 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t } //Okay, we seem to have data in the buffer. Grab the mux and copy it out if it's still there. portENTER_CRITICAL(&rb->mux); - itemData=getItemFromRingbuf(rb, item_size); + itemData=rb->getItemFromRingbufImpl(rb, item_size, wanted_size); portEXIT_CRITICAL(&rb->mux); if (itemData) { //We managed to get an item. @@ -409,6 +557,11 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t return (void*)itemData; } +void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait) +{ + return xRingbufferReceiveGeneric(ringbuf, item_size, ticks_to_wait, 0); +} + void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size) { @@ -416,7 +569,28 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size) uint8_t *itemData; configASSERT(rb); portENTER_CRITICAL_ISR(&rb->mux); - itemData=getItemFromRingbuf(rb, item_size); + itemData=rb->getItemFromRingbufImpl(rb, item_size, 0); + portEXIT_CRITICAL_ISR(&rb->mux); + return (void*)itemData; +} + +void *xRingbufferReceiveUpTo(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait, size_t wanted_size) { + ringbuf_t *rb=(ringbuf_t *)ringbuf; + if (wanted_size == 0) return NULL; + configASSERT(rb); + configASSERT(rb->flags & flag_bytebuf); + return xRingbufferReceiveGeneric(ringbuf, item_size, ticks_to_wait, wanted_size); +} + +void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size, size_t wanted_size) +{ + ringbuf_t *rb=(ringbuf_t *)ringbuf; + uint8_t *itemData; + if (wanted_size == 0) return NULL; + configASSERT(rb); + configASSERT(rb->flags & flag_bytebuf); + portENTER_CRITICAL_ISR(&rb->mux); + itemData=rb->getItemFromRingbufImpl(rb, item_size, 0); portEXIT_CRITICAL_ISR(&rb->mux); return (void*)itemData; } @@ -426,7 +600,7 @@ void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item) { ringbuf_t *rb=(ringbuf_t *)ringbuf; portENTER_CRITICAL_ISR(&rb->mux); - returnItemToRingbuf(rb, item); + rb->returnItemToRingbufImpl(rb, item); portEXIT_CRITICAL_ISR(&rb->mux); xSemaphoreGive(rb->free_space_sem); } @@ -436,7 +610,7 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t ringbuf, void *item, BaseType_ { ringbuf_t *rb=(ringbuf_t *)ringbuf; portENTER_CRITICAL_ISR(&rb->mux); - returnItemToRingbuf(rb, item); + rb->returnItemToRingbufImpl(rb, item); portEXIT_CRITICAL_ISR(&rb->mux); xSemaphoreGiveFromISR(rb->free_space_sem, higher_prio_task_awoken); } diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 5eb4687e06..88aa8d3ef5 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -77,6 +77,7 @@ task.h is included from an application file. */ #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #include "rom/ets_sys.h" +#include "esp_newlib.h" /* FreeRTOS includes. */ #include "FreeRTOS.h" @@ -85,7 +86,6 @@ task.h is included from an application file. */ #include "StackMacros.h" #include "portmacro.h" #include "semphr.h" -#include "sys/reent.h" /* Lint e961 and e750 are suppressed as a MISRA exception justified because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the @@ -140,6 +140,26 @@ typedef enum eNotified } eNotifyValue; +/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using +dynamically allocated RAM, in which case when any task is deleted it is known +that both the task's stack and TCB need to be freed. Sometimes the +FreeRTOSConfig.h settings only allow a task to be created using statically +allocated RAM, in which case when any task is deleted it is known that neither +the task's stack or TCB should be freed. Sometimes the FreeRTOSConfig.h +settings allow a task to be created using either statically or dynamically +allocated RAM, in which case a member of the TCB is used to record whether the +stack and/or TCB were allocated statically or dynamically, so when a task is +deleted the RAM that was allocated dynamically is freed again and no attempt is +made to free the RAM that was allocated statically. +tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a +task to be created using either statically or dynamically allocated RAM. Note +that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with +a statically allocated stack and a dynamically allocated TCB. */ +#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) ) +#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 ) +#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 ) +#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 ) + /* * Task control block. A task control block (TCB) is allocated for each task, * and stores task state information, including a pointer to the task's context @@ -151,7 +171,6 @@ typedef struct tskTaskControlBlock #if ( portUSING_MPU_WRAPPERS == 1 ) xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ - BaseType_t xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */ #endif ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ @@ -211,6 +230,12 @@ typedef struct tskTaskControlBlock volatile eNotifyValue eNotifyState; #endif + /* See the comments above the definition of + tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ + #endif + } tskTCB; /* The old tskTCB name is maintained above then typedefed to the new TCB_t name @@ -236,7 +261,7 @@ PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ -PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ +PRIVILEGED_DATA static List_t xPendingReadyList[ portNUM_PROCESSORS ]; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ #if ( INCLUDE_vTaskDelete == 1 ) @@ -263,7 +288,7 @@ PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; -PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; +PRIVILEGED_DATA static volatile BaseType_t xYieldPending[portNUM_PROCESSORS] = {pdFALSE}; PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = portMAX_DELAY; @@ -417,6 +442,9 @@ count overflows. */ vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) ) /*-----------------------------------------------------------*/ + +#define tskCAN_RUN_HERE( cpuid ) ( cpuid==xPortGetCoreID() || cpuid==tskNO_AFFINITY ) + /* * Several functions take an TaskHandle_t parameter that can optionally be NULL, * where NULL is used to indicate that the handle of the currently executing @@ -448,6 +476,7 @@ to its original value when it is released. */ #if configUSE_TICK_HOOK > 0 extern void vApplicationTickHook( void ); #endif +extern void esp_vApplicationTickHook( void ); #if portFIRST_TASK_HOOK extern void vPortFirstTaskHook(TaskFunction_t taskfn); @@ -456,12 +485,6 @@ to its original value when it is released. */ /* File private functions. --------------------------------*/ -/* - * Utility to ready a TCB for a given task. Mainly just copies the parameters - * into the TCB structure. - */ -static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth, const BaseType_t xCoreID ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - /** * Utility task that simply returns pdTRUE if the task referenced by xTask is * currently in the Suspended state, or pdFALSE if the task referenced by xTask @@ -516,12 +539,6 @@ static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; */ static void prvAddCurrentTaskToDelayedList( const portBASE_TYPE xCoreID, const TickType_t xTimeToWake ) PRIVILEGED_FUNCTION; -/* - * Allocates memory from the heap for a TCB and associated stack. Checks the - * allocation was successful. - */ -static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) PRIVILEGED_FUNCTION; - /* * Fills an TaskStatus_t structure with information on each task that is * referenced from the pxList list (which may be a ready list, a delayed list, @@ -578,120 +595,481 @@ static void prvResetNextTaskUnblockTime( void ); #endif +/* + * Called after a Task_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t * const xRegions, const BaseType_t xCoreID) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/* + * Called after a new task has been created and initialised to place the task + * under the control of the scheduler. + */ +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID ) PRIVILEGED_FUNCTION; + + /*-----------------------------------------------------------*/ -BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions, const BaseType_t xCoreID) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +/* + * This routine tries to send an interrupt to another core if needed to make it execute a task + * of higher priority. We try to figure out if needed first by inspecting the pxTCB of the + * other CPU first. Specifically for Xtensa, we can do this because pxTCB is an atomic pointer. It + * is possible that it is inaccurate because the other CPU just did a task switch, but in that case + * at most a superfluous interrupt is generated. +*/ +void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority ) { -BaseType_t xReturn; -TCB_t * pxNewTCB; -StackType_t *pxTopOfStack; -BaseType_t i; - configASSERT( pxTaskCode ); - configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) ); - configASSERT( (xCoreID>=0 && xCoreIDuxPriority < uxPriority ) { + vPortYieldOtherCore( xCoreID ); + } + } + else { - #if( portUSING_MPU_WRAPPERS == 1 ) - /* Should the task be created in privileged mode? */ - BaseType_t xRunPrivileged; - if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) + /* The task has no affinity. See if we can find a CPU to put it on.*/ + for (i=0; iuxPriority < uxPriority) { - xRunPrivileged = pdTRUE; + vPortYieldOtherCore( i ); + break; } - else - { - xRunPrivileged = pdFALSE; - } - uxPriority &= ~portPRIVILEGE_BIT; + } + } +} - if( puxStackBuffer != NULL ) - { - /* The application provided its own stack. Note this so no - attempt is made to delete the stack should that task be - deleted. */ - pxNewTCB->xUsingStaticallyAllocatedStack = pdTRUE; - } - else - { - /* The stack was allocated dynamically. Note this so it can be - deleted again if the task is deleted. */ - pxNewTCB->xUsingStaticallyAllocatedStack = pdFALSE; - } - #endif /* portUSING_MPU_WRAPPERS == 1 */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) - /* Calculate the top of stack address. This depends on whether the - stack grows from high memory to low (as per the 80x86) or vice versa. - portSTACK_GROWTH is used to make the result positive or negative as - required by the port. */ - #if( portSTACK_GROWTH < 0 ) + TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer, + const BaseType_t xCoreID ) + { + TCB_t *pxNewTCB; + TaskHandle_t xReturn; + + configASSERT( puxStackBuffer != NULL ); + configASSERT( pxTaskBuffer != NULL ); + configASSERT( (xCoreID>=0 && xCoreIDpxStack + ( usStackDepth - ( uint16_t ) 1 ); - pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ + /* The memory used for the task's TCB and stack are passed into this + function - use them. */ + pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; - /* Check the alignment of the calculated top of stack is correct. */ - configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note this + task was created statically in case the task is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL, xCoreID ); + prvAddNewTaskToReadyList( pxNewTCB, pxTaskCode, xCoreID ); + } + else + { + xReturn = NULL; + } + + return xReturn; + } + +#endif /* SUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( portUSING_MPU_WRAPPERS == 1 ) + + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) + { + TCB_t *pxNewTCB; + BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + + configASSERT( pxTaskDefinition->puxStackBuffer ); + + if( pxTaskDefinition->puxStackBuffer != NULL ) + { + /* Allocate space for the TCB. Where the memory comes from depends + on the implementation of the port malloc function and whether or + not static allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) + { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer; + + /* Tasks can be created statically or dynamically, so note + this task had a statically allocated stack in case it is + later deleted. The TCB was allocated dynamically. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY; + + prvInitialiseNewTask( pxTaskDefinition->pvTaskCode, + pxTaskDefinition->pcName, + ( uint32_t ) pxTaskDefinition->usStackDepth, + pxTaskDefinition->pvParameters, + pxTaskDefinition->uxPriority, + pxCreatedTask, pxNewTCB, + pxTaskDefinition->xRegions, + tskNO_AFFINITY ); + + prvAddNewTaskToReadyList( pxNewTCB, pxTaskDefinition->pvTaskCode, tskNO_AFFINITY ); + xReturn = pdPASS; + } + } + + return xReturn; + } + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + const BaseType_t xCoreID ) + { + TCB_t *pxNewTCB; + BaseType_t xReturn; + + /* If the stack grows down then allocate the stack then the TCB so the stack + does not grow into the TCB. Likewise if the stack grows up then allocate + the TCB then the stack. */ + #if( portSTACK_GROWTH > 0 ) + { + /* Allocate space for the TCB. Where the memory comes from depends on + the implementation of the port malloc function and whether or not static + allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) + { + /* Allocate space for the stack used by the task being created. + The base of the stack memory stored in the TCB so the task can + be deleted later if required. */ + pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + if( pxNewTCB->pxStack == NULL ) + { + /* Could not allocate the stack. Delete the allocated TCB. */ + vPortFree( pxNewTCB ); + pxNewTCB = NULL; + } + } } #else /* portSTACK_GROWTH */ { - pxTopOfStack = pxNewTCB->pxStack; + StackType_t *pxStack; - /* Check the alignment of the stack buffer is correct. */ - configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + /* Allocate space for the stack used by the task being created. */ + pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - /* If we want to use stack checking on architectures that use - a positive stack growth direction then we also need to store the - other extreme of the stack space. */ - pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); + if( pxStack != NULL ) + { + /* Allocate space for the TCB. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */ + + if( pxNewTCB != NULL ) + { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxStack; + } + else + { + /* The stack cannot be used as the TCB was not created. Free + it again. */ + vPortFree( pxStack ); + } + } + else + { + pxNewTCB = NULL; + } } #endif /* portSTACK_GROWTH */ - /* Setup the newly allocated TCB with the initial state of the task. */ - prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth, xCoreID ); + if( pxNewTCB != NULL ) + { + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note this + task was created dynamically in case it is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ - /* Initialize the TCB stack to look as if the task was already running, - but had been interrupted by the scheduler. The return address is set - to the start of the task function. Once the stack has been initialised - the top of stack variable is updated. */ - #if( portUSING_MPU_WRAPPERS == 1 ) - { - pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL, xCoreID ); + prvAddNewTaskToReadyList( pxNewTCB, pxTaskCode, xCoreID ); + xReturn = pdPASS; } - #else /* portUSING_MPU_WRAPPERS */ + else { - pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; } - #endif /* portUSING_MPU_WRAPPERS */ - if( ( void * ) pxCreatedTask != NULL ) + return xReturn; + } + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t * const xRegions, const BaseType_t xCoreID ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +StackType_t *pxTopOfStack; +UBaseType_t x; + + #if( portUSING_MPU_WRAPPERS == 1 ) + /* Should the task be created in privileged mode? */ + BaseType_t xRunPrivileged; + if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) { - /* Pass the TCB out - in an anonymous way. The calling function/ - task can use this as a handle to delete the task later if - required.*/ - *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; + xRunPrivileged = pdTRUE; + } + else + { + xRunPrivileged = pdFALSE; + } + uxPriority &= ~portPRIVILEGE_BIT; + #endif /* portUSING_MPU_WRAPPERS == 1 */ + + /* Avoid dependency on memset() if it is not required. */ + #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + { + /* Fill the stack with a known value to assist debugging. */ + ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) ); + } + #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ + + /* Calculate the top of stack address. This depends on whether the stack + grows from high memory to low (as per the 80x86) or vice versa. + portSTACK_GROWTH is used to make the result positive or negative as required + by the port. */ + #if( portSTACK_GROWTH < 0 ) + { + pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); + pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ + + /* Check the alignment of the calculated top of stack is correct. */ + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + } + #else /* portSTACK_GROWTH */ + { + pxTopOfStack = pxNewTCB->pxStack; + + /* Check the alignment of the stack buffer is correct. */ + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + + /* The other extreme of the stack space is required if stack checking is + performed. */ + pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); + } + #endif /* portSTACK_GROWTH */ + + /* Store the task name in the TCB. */ + for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + pxNewTCB->pcTaskName[ x ] = pcName[ x ]; + + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than + configMAX_TASK_NAME_LEN characters just in case the memory after the + string is not accessible (extremely unlikely). */ + if( pcName[ x ] == 0x00 ) + { + break; } else { mtCOVERAGE_TEST_MARKER(); } + } - /* Ensure interrupts don't access the task lists while they are being - updated. */ - taskENTER_CRITICAL(&xTaskQueueMutex); + /* Ensure the name string is terminated in the case that the string length + was greater or equal to configMAX_TASK_NAME_LEN. */ + pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; + + /* This is used as an array index so must ensure it's not too large. First + remove the privilege bit if one is present. */ + if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxNewTCB->uxPriority = uxPriority; + pxNewTCB->xCoreID = xCoreID; + #if ( configUSE_MUTEXES == 1 ) + { + pxNewTCB->uxBasePriority = uxPriority; + pxNewTCB->uxMutexesHeld = 0; + } + #endif /* configUSE_MUTEXES */ + + vListInitialiseItem( &( pxNewTCB->xGenericListItem ) ); + vListInitialiseItem( &( pxNewTCB->xEventListItem ) ); + + /* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get + back to the containing TCB from a generic item in a list. */ + listSET_LIST_ITEM_OWNER( &( pxNewTCB->xGenericListItem ), pxNewTCB ); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB ); + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + { + pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U; + } + #endif /* portCRITICAL_NESTING_IN_TCB */ + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + { + pxNewTCB->pxTaskTag = NULL; + } + #endif /* configUSE_APPLICATION_TASK_TAG */ + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxNewTCB->ulRunTimeCounter = 0UL; + } + #endif /* configGENERATE_RUN_TIME_STATS */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + { + vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth ); + } + #else + { + /* Avoid compiler warning about unreferenced parameter. */ + ( void ) xRegions; + } + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + { + for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) { - uxCurrentNumberOfTasks++; + pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL; + #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1) + pxNewTCB->pvThreadLocalStoragePointersDelCallback[ x ] = NULL; + #endif + } + } + #endif + + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + { + pxNewTCB->ulNotifiedValue = 0; + pxNewTCB->eNotifyState = eNotWaitingNotification; + } + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Initialise this task's Newlib reent structure. */ + esp_reent_init(&pxNewTCB->xNewLib_reent); + } + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + pxNewTCB->ucDelayAborted = pdFALSE; + } + #endif + + /* Initialize the TCB stack to look as if the task was already running, + but had been interrupted by the scheduler. The return address is set + to the start of the task function. Once the stack has been initialised + the top of stack variable is updated. */ + #if( portUSING_MPU_WRAPPERS == 1 ) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + } + #else /* portUSING_MPU_WRAPPERS */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + } + #endif /* portUSING_MPU_WRAPPERS */ + + if( ( void * ) pxCreatedTask != NULL ) + { + /* Pass the handle out in an anonymous way. The handle can be used to + change the created task's priority, delete the created task, etc.*/ + *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID ) +{ + BaseType_t i; + + /* Ensure interrupts don't access the task lists while the lists are being + updated. */ + taskENTER_CRITICAL(&xTaskQueueMutex); + { + uxCurrentNumberOfTasks++; + if( pxCurrentTCB[ xPortGetCoreID() ] == NULL ) + { + /* There are no other tasks, or all the other tasks are in + the suspended state - make this the current task. */ + pxCurrentTCB[ xPortGetCoreID() ] = pxNewTCB; + if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) { +#if portFIRST_TASK_HOOK + if ( xPortGetCoreID() == 0 ) { + vPortFirstTaskHook(pxTaskCode); + } +#endif /* configFIRST_TASK_HOOK */ /* This is the first task to be created so do the preliminary initialisation required. We will not recover if this call fails, but we will report the failure. */ prvInitialiseTaskLists(); } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* If the scheduler is not already running, make this task the + current task if it is the highest priority task to be created + so far. */ if( xSchedulerRunning == pdFALSE ) { /* Scheduler isn't running yet. We need to determine on which CPU to run this task. */ @@ -701,14 +1079,8 @@ BaseType_t i; if (xCoreID == tskNO_AFFINITY || xCoreID == i) { /* Schedule if nothing is scheduled yet, or overwrite a task of lower prio. */ - if ( pxCurrentTCB[i] == NULL || pxCurrentTCB[i]->uxPriority <= uxPriority ) + if ( pxCurrentTCB[i] == NULL || pxCurrentTCB[i]->uxPriority <= pxNewTCB->uxPriority ) { -#if portFIRST_TASK_HOOK - if ( i == 0) { - vPortFirstTaskHook(pxTaskCode); - } -#endif /* configFIRST_TASK_HOOK */ - pxCurrentTCB[i] = pxNewTCB; break; } @@ -719,44 +1091,45 @@ BaseType_t i; { mtCOVERAGE_TEST_MARKER(); } - - uxTaskNumber++; - - #if ( configUSE_TRACE_FACILITY == 1 ) - { - /* Add a counter into the TCB for tracing only. */ - pxNewTCB->uxTCBNumber = uxTaskNumber; - } - #endif /* configUSE_TRACE_FACILITY */ - traceTASK_CREATE( pxNewTCB ); - - prvAddTaskToReadyList( pxNewTCB ); - - xReturn = pdPASS; - portSETUP_TCB( pxNewTCB ); } - taskEXIT_CRITICAL(&xTaskQueueMutex); - } - else - { - xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; - traceTASK_CREATE_FAILED(); - } - if( xReturn == pdPASS ) + uxTaskNumber++; + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + /* Add a counter into the TCB for tracing only. */ + pxNewTCB->uxTCBNumber = uxTaskNumber; + } + #endif /* configUSE_TRACE_FACILITY */ + traceTASK_CREATE( pxNewTCB ); + + prvAddTaskToReadyList( pxNewTCB ); + + portSETUP_TCB( pxNewTCB ); + } + taskEXIT_CRITICAL(&xTaskQueueMutex); + + if( xSchedulerRunning != pdFALSE ) { - if( xSchedulerRunning != pdFALSE ) + /* Scheduler is running. If the created task is of a higher priority than an executing task + then it should run now. + ToDo: This only works for the current core. If a task is scheduled on an other processor, + the other processor will keep running the task it's working on, and only switch to the newer + task on a timer interrupt. */ + //No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. + if( pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < pxNewTCB->uxPriority ) { /* Scheduler is running. If the created task is of a higher priority than an executing task then it should run now. - ToDo: This only works for the current core. If a task is scheduled on an other processor, - the other processor will keep running the task it's working on, and only switch to the newer - task on a timer interrupt. */ - //No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. - if( pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < uxPriority ) + No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires. + */ + if( tskCAN_RUN_HERE( xCoreID ) && pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < pxNewTCB->uxPriority ) { taskYIELD_IF_USING_PREEMPTION(); } + else if( xCoreID != xPortGetCoreID() ) { + taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority); + } else { mtCOVERAGE_TEST_MARKER(); @@ -767,8 +1140,10 @@ BaseType_t i; mtCOVERAGE_TEST_MARKER(); } } - - return xReturn; + else + { + mtCOVERAGE_TEST_MARKER(); + } } /*-----------------------------------------------------------*/ @@ -834,7 +1209,7 @@ BaseType_t i; after which it is not possible to yield away from this task - hence xYieldPending is used to latch that a context switch is required. */ - portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); + portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending[xPortGetCoreID()] ); portYIELD_WITHIN_API(); } else @@ -1188,10 +1563,14 @@ BaseType_t i; /* The priority of a task other than the currently running task is being raised. Is the priority being raised above that of the running task? */ - if( uxNewPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + if ( tskCAN_RUN_HERE(pxTCB->xCoreID) && uxNewPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { xYieldRequired = pdTRUE; } + else if ( pxTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE( pxTCB->xCoreID, uxNewPriority ); + } else { mtCOVERAGE_TEST_MARKER(); @@ -1413,7 +1792,7 @@ BaseType_t i; if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE ) { /* Has the task already been resumed from within an ISR? */ - if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) + if( listIS_CONTAINED_WITHIN( &xPendingReadyList[ xPortGetCoreID() ], &( pxTCB->xEventListItem ) ) == pdFALSE ) { /* Is it in the suspended list because it is in the Suspended state, or because is is blocked with no timeout? */ @@ -1470,13 +1849,17 @@ BaseType_t i; prvAddTaskToReadyList( pxTCB ); /* We may have just resumed a higher priority task. */ - if( pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { /* This yield may not cause the task just resumed to run, but will leave the lists in the correct state for the next yield. */ taskYIELD_IF_USING_PREEMPTION_MUX(&xTaskQueueMutex); } + else if( pxTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority ); + } else { mtCOVERAGE_TEST_MARKER(); @@ -1501,7 +1884,6 @@ BaseType_t i; #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) -/* ToDo: Make this multicore-compatible. */ BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) { BaseType_t xYieldRequired = pdFALSE; @@ -1521,24 +1903,28 @@ BaseType_t i; { /* Ready lists can be accessed so move the task from the suspended list to the ready list directly. */ - if( pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + if( tskCAN_RUN_HERE( pxTCB->xCoreID ) && pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { xYieldRequired = pdTRUE; } + else if ( pxTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority); + } else { mtCOVERAGE_TEST_MARKER(); } - - ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); - prvAddTaskToReadyList( pxTCB ); } else { /* The delayed or ready lists cannot be accessed so the task is held in the pending ready list until the scheduler is unsuspended. */ - vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxTCB->xEventListItem ) ); } } else @@ -1723,18 +2109,19 @@ BaseType_t xAlreadyYielded = pdFALSE; { /* Move any readied tasks from the pending list into the appropriate ready list. */ - while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) + while( listLIST_IS_EMPTY( &xPendingReadyList[ xPortGetCoreID() ] ) == pdFALSE ) { - pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); + pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList[ xPortGetCoreID() ] ) ); ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); prvAddTaskToReadyList( pxTCB ); /* If the moved task has a priority higher than the current task then a yield must be performed. */ - if( pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + if ( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { - xYieldPending = pdTRUE; + /* We can schedule the awoken task on this CPU. */ + xYieldPending[xPortGetCoreID()] = pdTRUE; break; } else @@ -1753,7 +2140,7 @@ BaseType_t xAlreadyYielded = pdFALSE; { if( xTaskIncrementTick() != pdFALSE ) { - xYieldPending = pdTRUE; + xYieldPending[ xPortGetCoreID() ] = pdTRUE; } else { @@ -1767,7 +2154,7 @@ BaseType_t xAlreadyYielded = pdFALSE; mtCOVERAGE_TEST_MARKER(); } - if( xYieldPending == pdTRUE ) + if( xYieldPending[ xPortGetCoreID() ] == pdTRUE ) { #if( configUSE_PREEMPTION != 0 ) { @@ -1832,7 +2219,6 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) /*-----------------------------------------------------------*/ #if ( INCLUDE_pcTaskGetTaskName == 1 ) - char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { TCB_t *pxTCB; @@ -1975,6 +2361,22 @@ BaseType_t xSwitchRequired = pdFALSE; We can't really calculate what we need, that's done on core 0... just assume we need a switch. ToDo: Make this more intelligent? -- JD */ + { + /* Guard against the tick hook being called when the pended tick + count is being unwound (when the scheduler is being unlocked). */ + if( ( uxSchedulerSuspended[ xPortGetCoreID() ] != ( UBaseType_t ) pdFALSE ) || uxPendedTicks == ( UBaseType_t ) 0U ) + { + #if ( configUSE_TICK_HOOK == 1 ) + vApplicationTickHook(); + #endif /* configUSE_TICK_HOOK */ + esp_vApplicationTickHook(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + return pdTRUE; } @@ -2104,20 +2506,21 @@ BaseType_t xSwitchRequired = pdFALSE; } #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ - #if ( configUSE_TICK_HOOK == 1 ) { /* Guard against the tick hook being called when the pended tick count is being unwound (when the scheduler is being unlocked). */ if( uxPendedTicks == ( UBaseType_t ) 0U ) { + #if ( configUSE_TICK_HOOK == 1 ) vApplicationTickHook(); + #endif /* configUSE_TICK_HOOK */ + esp_vApplicationTickHook(); } else { mtCOVERAGE_TEST_MARKER(); } } - #endif /* configUSE_TICK_HOOK */ taskEXIT_CRITICAL_ISR(&xTaskQueueMutex); } else @@ -2131,11 +2534,12 @@ BaseType_t xSwitchRequired = pdFALSE; vApplicationTickHook(); } #endif + esp_vApplicationTickHook(); } #if ( configUSE_PREEMPTION == 1 ) { - if( xYieldPending != pdFALSE ) + if( xYieldPending [ xPortGetCoreID() ] != pdFALSE ) { xSwitchRequired = pdTRUE; } @@ -2251,11 +2655,11 @@ void vTaskSwitchContext( void ) { /* The scheduler is currently suspended - do not allow a context switch. */ - xYieldPending = pdTRUE; + xYieldPending[ xPortGetCoreID() ] = pdTRUE; } else { - xYieldPending = pdFALSE; + xYieldPending[ xPortGetCoreID() ] = pdFALSE; traceTASK_SWITCHED_OUT(); #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -2606,11 +3010,11 @@ BaseType_t xReturn; /* The delayed and ready lists cannot be accessed, so hold this task pending until the scheduler is resumed. */ taskENTER_CRITICAL(&xTaskQueueMutex); - vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); + vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxUnblockedTCB->xEventListItem ) ); taskEXIT_CRITICAL(&xTaskQueueMutex); } - if( pxUnblockedTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + if ( tskCAN_RUN_HERE(pxUnblockedTCB->xCoreID) && pxUnblockedTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { /* Return true if the task removed from the event list has a higher priority than the calling task. This allows the calling task to know if @@ -2619,7 +3023,12 @@ BaseType_t xReturn; /* Mark that a yield is pending in case the user is not using the "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ - xYieldPending = pdTRUE; + xYieldPending[ xPortGetCoreID() ] = pdTRUE; + } + else if ( pxUnblockedTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE( pxUnblockedTCB->xCoreID, pxUnblockedTCB->uxPriority ); + xReturn = pdFALSE; } else { @@ -2670,7 +3079,7 @@ BaseType_t xReturn; ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); prvAddTaskToReadyList( pxUnblockedTCB ); - if( pxUnblockedTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + if ( tskCAN_RUN_HERE(pxUnblockedTCB->xCoreID) && pxUnblockedTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { /* Return true if the task removed from the event list has a higher priority than the calling task. This allows @@ -2680,7 +3089,12 @@ BaseType_t xReturn; /* Mark that a yield is pending in case the user is not using the "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ - xYieldPending = pdTRUE; + xYieldPending[ xPortGetCoreID() ] = pdTRUE; + } + else if ( pxUnblockedTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE( pxUnblockedTCB->xCoreID, pxUnblockedTCB->uxPriority ); + xReturn = pdFALSE; } else { @@ -2751,7 +3165,7 @@ BaseType_t xReturn; void vTaskMissedYield( void ) { - xYieldPending = pdTRUE; + xYieldPending[ xPortGetCoreID() ] = pdTRUE; } /*-----------------------------------------------------------*/ @@ -2858,6 +3272,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) vApplicationIdleHook(); } #endif /* configUSE_IDLE_HOOK */ + { + /* Call the esp-idf hook system */ + extern void esp_vApplicationIdleHook( void ); + esp_vApplicationIdleHook(); + } + /* This conditional compilation should use inequality to 0, not equality to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when @@ -2916,12 +3336,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) eSleepModeStatus eReturn = eStandardSleep; taskENTER_CRITICAL(&xTaskQueueMutex); - if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) + if( listCURRENT_LIST_LENGTH( &xPendingReadyList[ xPortGetCoreID() ] ) != 0 ) { /* A task was made ready while the scheduler was suspended. */ eReturn = eAbortSleep; } - else if( xYieldPending != pdFALSE ) + else if( xYieldPending[ xPortGetCoreID() ] != pdFALSE ) { /* A yield was pended while the scheduler was suspended. */ eReturn = eAbortSleep; @@ -2955,120 +3375,6 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ -static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth, const BaseType_t xCoreID ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ -{ -UBaseType_t x; - - /* Store the task name in the TCB. */ - for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) - { - pxTCB->pcTaskName[ x ] = pcName[ x ]; - - /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than - configMAX_TASK_NAME_LEN characters just in case the memory after the - string is not accessible (extremely unlikely). */ - if( pcName[ x ] == 0x00 ) - { - break; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - - /* Ensure the name string is terminated in the case that the string length - was greater or equal to configMAX_TASK_NAME_LEN. */ - pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; - - /* This is used as an array index so must ensure it's not too large. First - remove the privilege bit if one is present. */ - if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) - { - uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - pxTCB->uxPriority = uxPriority; - pxTCB->xCoreID = xCoreID; - #if ( configUSE_MUTEXES == 1 ) - { - pxTCB->uxBasePriority = uxPriority; - pxTCB->uxMutexesHeld = 0; - } - #endif /* configUSE_MUTEXES */ - - vListInitialiseItem( &( pxTCB->xGenericListItem ) ); - vListInitialiseItem( &( pxTCB->xEventListItem ) ); - - /* Set the pxTCB as a link back from the ListItem_t. This is so we can get - back to the containing TCB from a generic item in a list. */ - listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB ); - - /* Event lists are always in priority order. */ - listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB ); - - #if ( portCRITICAL_NESTING_IN_TCB == 1 ) - { - pxTCB->uxCriticalNesting = ( UBaseType_t ) 0U; - } - #endif /* portCRITICAL_NESTING_IN_TCB */ - - #if ( configUSE_APPLICATION_TASK_TAG == 1 ) - { - pxTCB->pxTaskTag = NULL; - } - #endif /* configUSE_APPLICATION_TASK_TAG */ - - #if ( configGENERATE_RUN_TIME_STATS == 1 ) - { - pxTCB->ulRunTimeCounter = 0UL; - } - #endif /* configGENERATE_RUN_TIME_STATS */ - - #if ( portUSING_MPU_WRAPPERS == 1 ) - { - vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth ); - } - #else /* portUSING_MPU_WRAPPERS */ - { - ( void ) xRegions; - ( void ) usStackDepth; - } - #endif /* portUSING_MPU_WRAPPERS */ - - #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) - { - for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) - { - pxTCB->pvThreadLocalStoragePointers[ x ] = NULL; - #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) - pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] = (TlsDeleteCallbackFunction_t)NULL; - #endif - } - } - #endif - - - #if ( configUSE_TASK_NOTIFICATIONS == 1 ) - { - pxTCB->ulNotifiedValue = 0; - pxTCB->eNotifyState = eNotWaitingNotification; - } - #endif - - #if ( configUSE_NEWLIB_REENTRANT == 1 ) - { - /* Initialise this task's Newlib reent structure. */ - _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) ); - } - #endif /* configUSE_NEWLIB_REENTRANT */ -} -/*-----------------------------------------------------------*/ #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) @@ -3159,7 +3465,7 @@ UBaseType_t uxPriority; vListInitialise( &xDelayedTaskList1 ); vListInitialise( &xDelayedTaskList2 ); - vListInitialise( &xPendingReadyList ); + vListInitialise( &xPendingReadyList[ xPortGetCoreID() ] ); #if ( INCLUDE_vTaskDelete == 1 ) { @@ -3264,85 +3570,9 @@ static void prvAddCurrentTaskToDelayedList( const BaseType_t xCoreID, const Tick } /*-----------------------------------------------------------*/ -static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) -{ -TCB_t *pxNewTCB; - - /* If the stack grows down then allocate the stack then the TCB so the stack - does not grow into the TCB. Likewise if the stack grows up then allocate - the TCB then the stack. */ - #if( portSTACK_GROWTH > 0 ) - { - /* Allocate space for the TCB. Where the memory comes from depends on - the implementation of the port malloc function. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); - - if( pxNewTCB != NULL ) - { - /* Allocate space for the stack used by the task being created. - The base of the stack memory stored in the TCB so the task can - be deleted later if required. */ - pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - - if( pxNewTCB->pxStack == NULL ) - { - /* Could not allocate the stack. Delete the allocated TCB. */ - vPortFree( pxNewTCB ); - pxNewTCB = NULL; - } - } - } - #else /* portSTACK_GROWTH */ - { - StackType_t *pxStack; - - /* Allocate space for the stack used by the task being created. */ - pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - - if( pxStack != NULL ) - { - /* Allocate space for the TCB. Where the memory comes from depends - on the implementation of the port malloc function. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); - - if( pxNewTCB != NULL ) - { - /* Store the stack location in the TCB. */ - pxNewTCB->pxStack = pxStack; - } - else - { - /* The stack cannot be used as the TCB was not created. Free it - again. */ - vPortFree( pxStack ); - } - } - else - { - pxNewTCB = NULL; - } - } - #endif /* portSTACK_GROWTH */ - - if( pxNewTCB != NULL ) - { - /* Avoid dependency on memset() if it is not required. */ - #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) - { - /* Just to help debugging. */ - ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( StackType_t ) ); - } - #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ - } - - return pxNewTCB; -} -/*-----------------------------------------------------------*/ - BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) { TCB_t *pxTCB; - UBaseType_t uxReturn; pxTCB = prvGetTCBFromHandle( xTask ); @@ -3488,8 +3718,6 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) #if ( INCLUDE_vTaskDelete == 1 ) - // TODO: move this to newlib component and provide a header file - extern void _extra_cleanup_r(struct _reent* r); static void prvDeleteTCB( TCB_t *pxTCB ) { @@ -3502,27 +3730,44 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) to the task to free any memory allocated at the application level. */ #if ( configUSE_NEWLIB_REENTRANT == 1 ) { - pxTCB->xNewLib_reent.__cleanup = &_extra_cleanup_r; _reclaim_reent( &( pxTCB->xNewLib_reent ) ); } #endif /* configUSE_NEWLIB_REENTRANT */ - #if( portUSING_MPU_WRAPPERS == 1 ) + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) ) { - /* Only free the stack if it was allocated dynamically in the first - place. */ - if( pxTCB->xUsingStaticallyAllocatedStack == pdFALSE ) + /* The task can only have been allocated dynamically - free both + the stack and TCB. */ + vPortFreeAligned( pxTCB->pxStack ); + vPortFree( pxTCB ); + } + #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 ) + { + /* The task could have been allocated statically or dynamically, so + check what was statically allocated before trying to free the + memory. */ + if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ) { + /* Both the stack and TCB were allocated dynamically, so both + must be freed. */ vPortFreeAligned( pxTCB->pxStack ); + vPortFree( pxTCB ); + } + else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY ) + { + /* Only the stack was statically allocated, so the TCB is the + only memory that must be freed. */ + vPortFree( pxTCB ); + } + else + { + /* Neither the stack nor the TCB were allocated dynamically, so + nothing needs to be freed. */ + configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB ) + mtCOVERAGE_TEST_MARKER(); } } - #else - { - vPortFreeAligned( pxTCB->pxStack ); - } - #endif - - vPortFree( pxTCB ); + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ } #endif /* INCLUDE_vTaskDelete */ @@ -3567,6 +3812,19 @@ TCB_t *pxTCB; return xReturn; } + TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t cpuid ) + { + TaskHandle_t xReturn=NULL; + + //Xtensa-specific: the pxCurrentPCB pointer is atomic so we shouldn't need a lock. + if (cpuid < portNUM_PROCESSORS) { + xReturn = pxCurrentTCB[ cpuid ]; + } + + return xReturn; + } + + #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ /*-----------------------------------------------------------*/ @@ -3598,12 +3856,6 @@ TCB_t *pxTCB; #endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */ /*-----------------------------------------------------------*/ -/* -ToDo: Mutexes haven't been tested or adapted to multicore at all. - -In fact, nothing below this line has/is. -*/ - #if ( configUSE_MUTEXES == 1 ) void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) @@ -3756,9 +4008,8 @@ In fact, nothing below this line has/is. /* Gotcha (which seems to be deliberate in FreeRTOS, according to http://www.freertos.org/FreeRTOS_Support_Forum_Archive/December_2012/freertos_PIC32_Bug_-_vTaskEnterCritical_6400806.html -) is that calling vTaskEnterCritical followed by vTaskExitCritical will leave the interrupts DISABLED! Re-enabling the -scheduler will re-enable the interrupts instead. */ - +) is that calling vTaskEnterCritical followed by vTaskExitCritical will leave the interrupts DISABLED when the scheduler +is not running. Re-enabling the scheduler will re-enable the interrupts instead. */ #if ( portCRITICAL_NESTING_IN_TCB == 1 ) @@ -3931,7 +4182,9 @@ scheduler will re-enable the interrupts instead. */ function is executing. */ uxArraySize = uxCurrentNumberOfTasks; - /* Allocate an array index for each task. */ + /* Allocate an array index for each task. NOTE! if + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); if( pxTaskStatusArray != NULL ) @@ -3971,7 +4224,8 @@ scheduler will re-enable the interrupts instead. */ pcWriteBuffer += strlen( pcWriteBuffer ); } - /* Free the array again. */ + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ vPortFree( pxTaskStatusArray ); } else @@ -4030,7 +4284,9 @@ scheduler will re-enable the interrupts instead. */ function is executing. */ uxArraySize = uxCurrentNumberOfTasks; - /* Allocate an array index for each task. */ + /* Allocate an array index for each task. NOTE! If + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); if( pxTaskStatusArray != NULL ) @@ -4096,7 +4352,8 @@ scheduler will re-enable the interrupts instead. */ mtCOVERAGE_TEST_MARKER(); } - /* Free the array again. */ + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ vPortFree( pxTaskStatusArray ); } else @@ -4436,12 +4693,16 @@ TickType_t uxReturn; /* The task should not have been on an event list. */ configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); - if( pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { /* The notified task has a priority above the currently executing task so a yield is required. */ portYIELD_WITHIN_API(); } + else if ( pxTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE(pxTCB->xCoreID, pxTCB->uxPriority); + } else { mtCOVERAGE_TEST_MARKER(); @@ -4529,10 +4790,10 @@ TickType_t uxReturn; { /* The delayed and ready lists cannot be accessed, so hold this task pending until the scheduler is resumed. */ - vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxTCB->xEventListItem ) ); } - if( pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { /* The notified task has a priority above the currently executing task so a yield is required. */ @@ -4541,6 +4802,10 @@ TickType_t uxReturn; *pxHigherPriorityTaskWoken = pdTRUE; } } + else if ( pxTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority ); + } else { mtCOVERAGE_TEST_MARKER(); @@ -4593,10 +4858,10 @@ TickType_t uxReturn; { /* The delayed and ready lists cannot be accessed, so hold this task pending until the scheduler is resumed. */ - vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxTCB->xEventListItem ) ); } - - if( pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + + if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { /* The notified task has a priority above the currently executing task so a yield is required. */ @@ -4605,6 +4870,10 @@ TickType_t uxReturn; *pxHigherPriorityTaskWoken = pdTRUE; } } + else if ( pxTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority ); + } else { mtCOVERAGE_TEST_MARKER(); diff --git a/components/freertos/xtensa_intr.c b/components/freertos/xtensa_intr.c index f5ca7d151f..e9c0b79b96 100644 --- a/components/freertos/xtensa_intr.c +++ b/components/freertos/xtensa_intr.c @@ -30,7 +30,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include +#include "freertos/FreeRTOS.h" #include "freertos/xtensa_api.h" +#include "freertos/portable.h" #include "rom/ets_sys.h" @@ -39,7 +41,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* Handler table is in xtensa_intr_asm.S */ // Todo: Make multicore - JD -extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM]; +extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM*portNUM_PROCESSORS]; /* @@ -66,6 +68,8 @@ xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f) if( n < 0 || n >= XCHAL_EXCCAUSE_NUM ) return 0; /* invalid exception number */ + /* Convert exception number to _xt_exception_table name */ + n = n * portNUM_PROCESSORS + xPortGetCoreID(); old = _xt_exception_table[n]; if (f) { @@ -89,7 +93,7 @@ typedef struct xt_handler_table_entry { void * arg; } xt_handler_table_entry; -extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS]; +extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS]; /* @@ -118,6 +122,9 @@ xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg) if( Xthal_intlevel[n] > XCHAL_EXCM_LEVEL ) return 0; /* priority level too high to safely handle in C */ + /* Convert exception number to _xt_exception_table name */ + n = n * portNUM_PROCESSORS + xPortGetCoreID(); + entry = _xt_interrupt_table + n; old = entry->handler; diff --git a/components/freertos/xtensa_intr_asm.S b/components/freertos/xtensa_intr_asm.S index 5f9890dfe4..8c7ae63fdb 100644 --- a/components/freertos/xtensa_intr_asm.S +++ b/components/freertos/xtensa_intr_asm.S @@ -30,6 +30,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include "xtensa_context.h" +#include "FreeRTOSConfig.h" #if XCHAL_HAVE_INTERRUPTS @@ -59,6 +60,15 @@ _xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */ Table of C-callable interrupt handlers for each interrupt. Note that not all slots can be filled, because interrupts at level > EXCM_LEVEL will not be dispatched to a C handler by default. + + Stored as: + int 0 cpu 0 + int 0 cpu 1 + ... + int 0 cpu n + int 1 cpu 0 + int 1 cpu 1 + etc ------------------------------------------------------------------------------- */ @@ -69,7 +79,7 @@ _xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */ _xt_interrupt_table: .set i, 0 - .rept XCHAL_NUM_INTERRUPTS + .rept XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS .word xt_unhandled_interrupt /* handler address */ .word i /* handler arg (default: intnum) */ .set i, i+1 @@ -85,6 +95,15 @@ _xt_interrupt_table: Table of C-callable exception handlers for each exception. Note that not all slots will be active, because some exceptions (e.g. coprocessor exceptions) are always handled by the OS and cannot be hooked by user handlers. + + Stored as: + exc 0 cpu 0 + exc 0 cpu 1 + ... + exc 0 cpu n + exc 1 cpu 0 + exc 1 cpu 1 + etc ------------------------------------------------------------------------------- */ @@ -93,7 +112,7 @@ _xt_interrupt_table: .align 4 _xt_exception_table: - .rept XCHAL_EXCCAUSE_NUM + .rept XCHAL_EXCCAUSE_NUM * portNUM_PROCESSORS .word xt_unhandled_exception /* handler address */ .endr diff --git a/components/freertos/xtensa_vectors.S b/components/freertos/xtensa_vectors.S index f0d874a59c..f180705e70 100644 --- a/components/freertos/xtensa_vectors.S +++ b/components/freertos/xtensa_vectors.S @@ -91,12 +91,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *******************************************************************************/ #include "xtensa_rtos.h" - +#include "esp_panic.h" +#include "sdkconfig.h" /* Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used. Please change this when the tcb structure is changed */ -#define TASKTCB_XCOREID_OFFSET (0x3C+configMAX_TASK_NAME_LEN+3)&~3 +#define TASKTCB_XCOREID_OFFSET (0x38+configMAX_TASK_NAME_LEN+3)&~3 .extern pxCurrentTCB /* Enable stack backtrace across exception/interrupt - see below */ @@ -112,6 +113,27 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define XIE_ARG 4 #define XIE_SIZE 8 + +/* + Macro get_percpu_entry_for - convert a per-core ID into a multicore entry. + Basically does reg=reg*portNUM_PROCESSORS+current_core_id + Multiple versions here to optimize for specific portNUM_PROCESSORS values. +*/ + .macro get_percpu_entry_for reg scratch +#if (portNUM_PROCESSORS == 1) + /* No need to do anything */ +#elif (portNUM_PROCESSORS == 2) + /* Optimized 2-core code. */ + getcoreid \scratch + addx2 \reg,\reg,\scratch +#else + /* Generalized n-core code. Untested! */ + movi \scratch,portNUM_PROCESSORS + mull \scratch,\reg,\scratch + getcoreid \reg + add \reg,\scratch,\reg +#endif + .endm /* -------------------------------------------------------------------------------- Macro extract_msb - return the input with only the highest bit set. @@ -228,6 +250,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */ + get_percpu_entry_for a3, a12 movi a4, _xt_interrupt_table addx8 a3, a3, a4 /* a3 = address of interrupt table entry */ l32i a4, a3, XIE_HANDLER /* a4 = handler address */ @@ -302,12 +325,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ .section .iram1,"ax" - .global panicHandler + .global panicHandler .global _xt_panic .type _xt_panic,@function .align 4 - .literal_position + .literal_position .align 4 _xt_panic: @@ -339,45 +362,45 @@ _xt_panic: rsr a0, EXCSAVE_1 /* save interruptee's a0 */ s32i a0, sp, XT_STK_A0 - /* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */ - movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE + /* Set up PS for C, disable all interrupts, and clear EXCM. */ + movi a0, PS_INTLEVEL(7) | PS_UM | PS_WOE wsr a0, PS - //Call panic handler - mov a2,sp - call4 panicHandler + //Call panic handler + mov a6,sp + call4 panicHandler 1: j 1b /* loop infinitely */ - retw + retw - .align 4 + .align 4 //Call using call0. Prints the hex char in a2. Kills a3, a4, a5 panic_print_hex: - movi a3,0x60000000 - movi a4,8 + movi a3,0x60000000 + movi a4,8 panic_print_hex_loop: - l32i a5, a3, 0x1c - extui a5, a5, 16, 8 - bgei a5,64,panic_print_hex_loop + l32i a5, a3, 0x1c + extui a5, a5, 16, 8 + bgei a5,64,panic_print_hex_loop - srli a5,a2,28 - bgei a5,10,panic_print_hex_a - addi a5,a5,'0' - j panic_print_hex_ok + srli a5,a2,28 + bgei a5,10,panic_print_hex_a + addi a5,a5,'0' + j panic_print_hex_ok panic_print_hex_a: - addi a5,a5,'A'-10 + addi a5,a5,'A'-10 panic_print_hex_ok: - s32i a5,a3,0 - slli a2,a2,4 - - addi a4,a4,-1 - bnei a4,0,panic_print_hex_loop - movi a5,' ' - s32i a5,a3,0 + s32i a5,a3,0 + slli a2,a2,4 + + addi a4,a4,-1 + bnei a4,0,panic_print_hex_loop + movi a5,' ' + s32i a5,a3,0 - ret + ret @@ -394,6 +417,9 @@ panic_print_hex_ok: with index 0 containing the entry for user exceptions. Initialized with all 0s, meaning no handler is installed at each level. See comment in xtensa_rtos.h for more details. + + *WARNING* This array is for all CPUs, that is, installing a hook for + one CPU will install it for all others as well! -------------------------------------------------------------------------------- */ @@ -462,6 +488,8 @@ _DebugExceptionVector: jx a3 #else wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */ + movi a0,PANIC_RSN_DEBUGEXCEPTION + wsr a0,EXCCAUSE call0 _xt_panic /* does not return */ rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */ #endif @@ -489,6 +517,8 @@ _DoubleExceptionVector: #if XCHAL_HAVE_DEBUG break 1, 4 /* unhandled double exception */ #endif + movi a0,PANIC_RSN_DOUBLEEXCEPTION + wsr a0,EXCCAUSE call0 _xt_panic /* does not return */ rfde /* make a0 point here not later */ @@ -522,6 +552,8 @@ _xt_kernel_exc: #if XCHAL_HAVE_DEBUG break 1, 0 /* unhandled kernel exception */ #endif + movi a0,PANIC_RSN_KERNELEXCEPTION + wsr a0,EXCCAUSE call0 _xt_panic /* does not return */ rfe /* make a0 point here not there */ @@ -681,6 +713,7 @@ _xt_user_exc: rsr a2, EXCCAUSE /* recover exc cause */ movi a3, _xt_exception_table + get_percpu_entry_for a3, a4 addx4 a4, a2, a3 /* a4 = address of exception table entry */ l32i a4, a4, 0 /* a4 = handler address */ #ifdef __XTENSA_CALL0_ABI__ @@ -904,19 +937,16 @@ _xt_coproc_exc: core we're running on now. */ movi a2, pxCurrentTCB getcoreid a3 - slli a3, a3, 2 - add a2, a2, a3 + addx4 a2, a3, a2 l32i a2, a2, 0 /* a2 = start of pxCurrentTCB[cpuid] */ addi a2, a2, TASKTCB_XCOREID_OFFSET /* offset to xCoreID in tcb struct */ - getcoreid a3 s32i a3, a2, 0 /* store current cpuid */ - /* Grab correct xt_coproc_owner_sa for this core */ - getcoreid a2 - movi a3, XCHAL_CP_MAX << 2 - mull a2, a2, a3 + /* Grab correct xt_coproc_owner_sa for this core */ + movi a2, XCHAL_CP_MAX << 2 + mull a2, a2, a3 movi a3, _xt_coproc_owner_sa /* a3 = base of owner array */ - add a3, a3, a2 + add a3, a3, a2 extui a2, a0, 0, 16 /* coprocessor bitmask portion */ or a4, a4, a2 /* a4 = CPENABLE | (1 << n) */ @@ -1027,6 +1057,8 @@ _xt_coproc_exc: #if XCHAL_HAVE_DEBUG break 1, 1 /* unhandled user exception */ #endif + movi a0,PANIC_RSN_COPROCEXCEPTION + wsr a0,EXCCAUSE call0 _xt_panic /* not in a thread (invalid) */ /* never returns */ @@ -1610,6 +1642,28 @@ _xt_highint4: ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE. */ + + + /* On the ESP32, this level is used for the INT_WDT handler. If that triggers, the program is stuck with interrupts + off and the CPU should panic. */ + rsr a0, EXCSAVE_4 + wsr a0, EXCSAVE_1 /* panic handler reads this register */ + /* Set EXCCAUSE to reflect cause of the wdt int trigger */ + movi a0,PANIC_RSN_INTWDT_CPU0 + wsr a0,EXCCAUSE +#if CONFIG_INT_WDT_CHECK_CPU1 + /* Check if the cause is the app cpu failing to tick.*/ + movi a0, int_wdt_app_cpu_ticked + l32i a0, a0, 0 + bnez a0, 1f + /* It is. Modify cause. */ + movi a0,PANIC_RSN_INTWDT_CPU1 + wsr a0,EXCCAUSE +1: +#endif + call0 _xt_panic + + .align 4 .L_xt_highint4_exit: rsr a0, EXCSAVE_4 /* restore a0 */ diff --git a/components/freertos/xtensa_vectors.S-new b/components/freertos/xtensa_vectors.S-new deleted file mode 100644 index 88349eee9f..0000000000 --- a/components/freertos/xtensa_vectors.S-new +++ /dev/null @@ -1,1915 +0,0 @@ -/******************************************************************************* -Copyright (c) 2006-2015 Cadence Design Systems Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------- - - XTENSA VECTORS AND LOW LEVEL HANDLERS FOR AN RTOS - - Xtensa low level exception and interrupt vectors and handlers for an RTOS. - - Interrupt handlers and user exception handlers support interaction with - the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT before and - after user's specific interrupt handlers. These macros are defined in - xtensa_.h to call suitable functions in a specific RTOS. - - Users can install application-specific interrupt handlers for low and - medium level interrupts, by calling xt_set_interrupt_handler(). These - handlers can be written in C, and must obey C calling convention. The - handler table is indexed by the interrupt number. Each handler may be - provided with an argument. - - Note that the system timer interrupt is handled specially, and is - dispatched to the RTOS-specific handler. This timer cannot be hooked - by application code. - - Optional hooks are also provided to install a handler per level at - run-time, made available by compiling this source file with - '-DXT_INTEXC_HOOKS' (useful for automated testing). - -!! This file is a template that usually needs to be modified to handle !! -!! application specific interrupts. Search USER_EDIT for helpful comments !! -!! on where to insert handlers and how to write them. !! - - Users can also install application-specific exception handlers in the - same way, by calling xt_set_exception_handler(). One handler slot is - provided for each exception type. Note that some exceptions are handled - by the porting layer itself, and cannot be taken over by application - code in this manner. These are the alloca, syscall, and coprocessor - exceptions. - - The exception handlers can be written in C, and must follow C calling - convention. Each handler is passed a pointer to an exception frame as - its single argument. The exception frame is created on the stack, and - holds the saved context of the thread that took the exception. If the - handler returns, the context will be restored and the instruction that - caused the exception will be retried. If the handler makes any changes - to the saved state in the exception frame, the changes will be applied - when restoring the context. - - Because Xtensa is a configurable architecture, this port supports all user - generated configurations (except restrictions stated in the release notes). - This is accomplished by conditional compilation using macros and functions - defined in the Xtensa HAL (hardware adaptation layer) for your configuration. - Only the relevant parts of this file will be included in your RTOS build. - For example, this file provides interrupt vector templates for all types and - all priority levels, but only the ones in your configuration are built. - - NOTES on the use of 'call0' for long jumps instead of 'j': - 1. This file should be assembled with the -mlongcalls option to xt-xcc. - 2. The -mlongcalls compiler option causes 'call0 dest' to be expanded to - a sequence 'l32r a0, dest' 'callx0 a0' which works regardless of the - distance from the call to the destination. The linker then relaxes - it back to 'call0 dest' if it determines that dest is within range. - This allows more flexibility in locating code without the performance - overhead of the 'l32r' literal data load in cases where the destination - is in range of 'call0'. There is an additional benefit in that 'call0' - has a longer range than 'j' due to the target being word-aligned, so - the 'l32r' sequence is less likely needed. - 3. The use of 'call0' with -mlongcalls requires that register a0 not be - live at the time of the call, which is always the case for a function - call but needs to be ensured if 'call0' is used as a jump in lieu of 'j'. - 4. This use of 'call0' is independent of the C function call ABI. - -*******************************************************************************/ - -#include "xtensa_rtos.h" - - -/* Enable stack backtrace across exception/interrupt - see below */ -#define XT_DEBUG_BACKTRACE 1 - - -/* --------------------------------------------------------------------------------- - Defines used to access _xtos_interrupt_table. --------------------------------------------------------------------------------- -*/ -#define XIE_HANDLER 0 -#define XIE_ARG 4 -#define XIE_SIZE 8 - -/* --------------------------------------------------------------------------------- - Macro extract_msb - return the input with only the highest bit set. - - Input : "ain" - Input value, clobbered. - Output : "aout" - Output value, has only one bit set, MSB of "ain". - The two arguments must be different AR registers. --------------------------------------------------------------------------------- -*/ - - .macro extract_msb aout ain -1: - addi \aout, \ain, -1 /* aout = ain - 1 */ - and \ain, \ain, \aout /* ain = ain & aout */ - bnez \ain, 1b /* repeat until ain == 0 */ - addi \aout, \aout, 1 /* return aout + 1 */ - .endm - -/* --------------------------------------------------------------------------------- - Macro dispatch_c_isr - dispatch interrupts to user ISRs. - This will dispatch to user handlers (if any) that are registered in the - XTOS dispatch table (_xtos_interrupt_table). These handlers would have - been registered by calling _xtos_set_interrupt_handler(). There is one - exception - the timer interrupt used by the OS will not be dispatched - to a user handler - this must be handled by the caller of this macro. - - Level triggered and software interrupts are automatically deasserted by - this code. - - ASSUMPTIONS: - -- PS.INTLEVEL is set to "level" at entry - -- PS.EXCM = 0, C calling enabled - - NOTE: For CALL0 ABI, a12-a15 have not yet been saved. - - NOTE: This macro will use registers a0 and a2-a6. The arguments are: - level -- interrupt level - mask -- interrupt bitmask for this level --------------------------------------------------------------------------------- -*/ - - .macro dispatch_c_isr level mask - - /* Get mask of pending, enabled interrupts at this level into a2. */ - -.L_xt_user_int_&level&: - rsr a2, INTENABLE - rsr a3, INTERRUPT - movi a4, \mask - and a2, a2, a3 - and a2, a2, a4 - beqz a2, 9f /* nothing to do */ - - /* This bit of code provides a nice debug backtrace in the debugger. - It does take a few more instructions, so undef XT_DEBUG_BACKTRACE - if you want to save the cycles. - */ - #if XT_DEBUG_BACKTRACE - #ifndef __XTENSA_CALL0_ABI__ - rsr a0, EPC_1 + \level - 1 /* return address */ - movi a4, 0xC0000000 /* constant with top 2 bits set (call size) */ - or a0, a0, a4 /* set top 2 bits */ - addx2 a0, a4, a0 /* clear top bit -- simulating call4 size */ - #endif - #endif - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a4, _xt_intexc_hooks - l32i a4, a4, \level << 2 - beqz a4, 2f - #ifdef __XTENSA_CALL0_ABI__ - callx0 a4 - beqz a2, 9f - #else - mov a6, a2 - callx4 a4 - beqz a6, 9f - mov a2, a6 - #endif -2: - #endif - - /* Now look up in the dispatch table and call user ISR if any. */ - /* If multiple bits are set then MSB has highest priority. */ - - extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */ - - #ifdef XT_USE_SWPRI - /* Enable all interrupts at this level that are numerically higher - than the one we just selected, since they are treated as higher - priority. - */ - movi a3, \mask /* a3 = all interrupts at this level */ - add a2, a4, a4 /* a2 = a4 << 1 */ - addi a2, a2, -1 /* a2 = mask of 1's <= a4 bit */ - and a2, a2, a3 /* a2 = mask of all bits <= a4 at this level */ - movi a3, _xt_intdata - l32i a6, a3, 4 /* a6 = _xt_vpri_mask */ - neg a2, a2 - addi a2, a2, -1 /* a2 = mask to apply */ - and a5, a6, a2 /* mask off all bits <= a4 bit */ - s32i a5, a3, 4 /* update _xt_vpri_mask */ - rsr a3, INTENABLE - and a3, a3, a2 /* mask off all bits <= a4 bit */ - wsr a3, INTENABLE - rsil a3, \level - 1 /* lower interrupt level by 1 */ - #endif - - movi a3, XT_TIMER_INTEN /* a3 = timer interrupt bit */ - wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */ - beq a3, a4, 7f /* if timer interrupt then skip table */ - - find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */ - - movi a4, _xt_interrupt_table - addx8 a3, a3, a4 /* a3 = address of interrupt table entry */ - l32i a4, a3, XIE_HANDLER /* a4 = handler address */ - #ifdef __XTENSA_CALL0_ABI__ - mov a12, a6 /* save in callee-saved reg */ - l32i a2, a3, XIE_ARG /* a2 = handler arg */ - callx0 a4 /* call handler */ - mov a2, a12 - #else - mov a2, a6 /* save in windowed reg */ - l32i a6, a3, XIE_ARG /* a6 = handler arg */ - callx4 a4 /* call handler */ - #endif - - #ifdef XT_USE_SWPRI - j 8f - #else - j .L_xt_user_int_&level& /* check for more interrupts */ - #endif - -7: - - .ifeq XT_TIMER_INTPRI - \level -.L_xt_user_int_timer_&level&: - /* - Interrupt handler for the RTOS tick timer if at this level. - We'll be reading the interrupt state again after this call - so no need to preserve any registers except a6 (vpri_mask). - */ - - #ifdef __XTENSA_CALL0_ABI__ - mov a12, a6 - call0 XT_RTOS_TIMER_INT - mov a2, a12 - #else - mov a2, a6 - call4 XT_RTOS_TIMER_INT - #endif - .endif - - #ifdef XT_USE_SWPRI - j 8f - #else - j .L_xt_user_int_&level& /* check for more interrupts */ - #endif - - #ifdef XT_USE_SWPRI -8: - /* Restore old value of _xt_vpri_mask from a2. Also update INTENABLE from - virtual _xt_intenable which _could_ have changed during interrupt - processing. */ - - movi a3, _xt_intdata - l32i a4, a3, 0 /* a4 = _xt_intenable */ - s32i a2, a3, 4 /* update _xt_vpri_mask */ - and a4, a4, a2 /* a4 = masked intenable */ - wsr a4, INTENABLE /* update INTENABLE */ - #endif - -9: - /* done */ - - .endm - - -/* --------------------------------------------------------------------------------- - Panic handler. - Should be reached by call0 (preferable) or jump only. If call0, a0 says where - from. If on simulator, display panic message and abort, else loop indefinitely. --------------------------------------------------------------------------------- -*/ - - .text - .global _xt_panic - .type _xt_panic,@function - .align 4 - -_xt_panic: - #ifdef XT_SIMULATOR - addi a4, a0, -3 /* point to call0 */ - movi a3, _xt_panic_message - movi a2, SYS_log_msg - simcall - movi a2, SYS_gdb_abort - simcall - #else - rsil a2, XCHAL_EXCM_LEVEL /* disable all low & med ints */ -1: j 1b /* loop infinitely */ - #endif - - .section .rodata, "a" - .align 4 - -_xt_panic_message: - .string "\n*** _xt_panic() was called from 0x%08x or jumped to. ***\n" - - -/* --------------------------------------------------------------------------------- - Hooks to dynamically install handlers for exceptions and interrupts. - Allows automated regression frameworks to install handlers per test. - Consists of an array of function pointers indexed by interrupt level, - with index 0 containing the entry for user exceptions. - Initialized with all 0s, meaning no handler is installed at each level. - See comment in xtensa_rtos.h for more details. --------------------------------------------------------------------------------- -*/ - - #ifdef XT_INTEXC_HOOKS - .data - .global _xt_intexc_hooks - .type _xt_intexc_hooks,@object - .align 4 - -_xt_intexc_hooks: - .fill XT_INTEXC_HOOK_NUM, 4, 0 - #endif - - -/* --------------------------------------------------------------------------------- - EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS - (except window exception vectors). - - Each vector goes at a predetermined location according to the Xtensa - hardware configuration, which is ensured by its placement in a special - section known to the Xtensa linker support package (LSP). It performs - the minimum necessary before jumping to the handler in the .text section. - - The corresponding handler goes in the normal .text section. It sets up - the appropriate stack frame, saves a few vector-specific registers and - calls XT_RTOS_INT_ENTER to save the rest of the interrupted context - and enter the RTOS, then sets up a C environment. It then calls the - user's interrupt handler code (which may be coded in C) and finally - calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling. - - While XT_RTOS_INT_EXIT does not return directly to the interruptee, - eventually the RTOS scheduler will want to dispatch the interrupted - task or handler. The scheduler will return to the exit point that was - saved in the interrupt stack frame at XT_STK_EXIT. --------------------------------------------------------------------------------- -*/ - - -/* --------------------------------------------------------------------------------- -Debug Exception. --------------------------------------------------------------------------------- -*/ - -#if XCHAL_HAVE_DEBUG - - .begin literal_prefix .DebugExceptionVector - .section .DebugExceptionVector.text, "ax" - .global _DebugExceptionVector - .align 4 - -_DebugExceptionVector: - - #ifdef XT_SIMULATOR - /* - In the simulator, let the debugger (if any) handle the debug exception, - or simply stop the simulation: - */ - wsr a2, EXCSAVE+XCHAL_DEBUGLEVEL /* save a2 where sim expects it */ - movi a2, SYS_gdb_enter_sktloop - simcall /* have ISS handle debug exc. */ - #elif 0 /* change condition to 1 to use the HAL minimal debug handler */ - wsr a3, EXCSAVE+XCHAL_DEBUGLEVEL - movi a3, xthal_debugexc_defhndlr_nw /* use default debug handler */ - jx a3 - #else - wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */ - call0 _xt_panic /* does not return */ - rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */ - #endif - - .end literal_prefix - -#endif - -/* --------------------------------------------------------------------------------- -Double Exception. -Double exceptions are not a normal occurrence. They indicate a bug of some kind. --------------------------------------------------------------------------------- -*/ - -#ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR - - .begin literal_prefix .DoubleExceptionVector - .section .DoubleExceptionVector.text, "ax" - .global _DoubleExceptionVector - .align 4 - -_DoubleExceptionVector: - - #if XCHAL_HAVE_DEBUG - break 1, 4 /* unhandled double exception */ - #endif - call0 _xt_panic /* does not return */ - rfde /* make a0 point here not later */ - - .end literal_prefix - -#endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */ - -/* --------------------------------------------------------------------------------- -Kernel Exception (including Level 1 Interrupt from kernel mode). --------------------------------------------------------------------------------- -*/ - - .begin literal_prefix .KernelExceptionVector - .section .KernelExceptionVector.text, "ax" - .global _KernelExceptionVector - .align 4 - -_KernelExceptionVector: - - wsr a0, EXCSAVE_1 /* preserve a0 */ - call0 _xt_kernel_exc /* kernel exception handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .align 4 - -_xt_kernel_exc: - #if XCHAL_HAVE_DEBUG - break 1, 0 /* unhandled kernel exception */ - #endif - call0 _xt_panic /* does not return */ - rfe /* make a0 point here not there */ - - -/* --------------------------------------------------------------------------------- -User Exception (including Level 1 Interrupt from user mode). --------------------------------------------------------------------------------- -*/ - - .begin literal_prefix .UserExceptionVector - .section .UserExceptionVector.text, "ax" - .global _UserExceptionVector - .type _UserExceptionVector,@function - .align 4 - -_UserExceptionVector: - - wsr a0, EXCSAVE_1 /* preserve a0 */ - call0 _xt_user_exc /* user exception handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - -/* --------------------------------------------------------------------------------- - Insert some waypoints for jumping beyond the signed 8-bit range of - conditional branch instructions, so the conditional branchces to specific - exception handlers are not taken in the mainline. Saves some cycles in the - mainline. --------------------------------------------------------------------------------- -*/ - - .text - - #if XCHAL_HAVE_WINDOWED - .align 4 -_xt_to_alloca_exc: - call0 _xt_alloca_exc /* in window vectors section */ - /* never returns here - call0 is used as a jump (see note at top) */ - #endif - - .align 4 -_xt_to_syscall_exc: - call0 _xt_syscall_exc - /* never returns here - call0 is used as a jump (see note at top) */ - - #if XCHAL_CP_NUM > 0 - .align 4 -_xt_to_coproc_exc: - call0 _xt_coproc_exc - /* never returns here - call0 is used as a jump (see note at top) */ - #endif - - -/* --------------------------------------------------------------------------------- - User exception handler. --------------------------------------------------------------------------------- -*/ - - .type _xt_user_exc,@function - .align 4 - -_xt_user_exc: - - /* If level 1 interrupt then jump to the dispatcher */ - rsr a0, EXCCAUSE - beqi a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_lowint1 - - /* Handle any coprocessor exceptions. Rely on the fact that exception - numbers above EXCCAUSE_CP0_DISABLED all relate to the coprocessors. - */ - #if XCHAL_CP_NUM > 0 - bgeui a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc - #endif - - /* Handle alloca and syscall exceptions */ - #if XCHAL_HAVE_WINDOWED - beqi a0, EXCCAUSE_ALLOCA, _xt_to_alloca_exc - #endif - beqi a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc - - /* Handle all other exceptions. All can have user-defined handlers. */ - /* NOTE: we'll stay on the user stack for exception handling. */ - - /* Allocate exception frame and save minimal context. */ - mov a0, sp - addi sp, sp, -XT_STK_FRMSZ - s32i a0, sp, XT_STK_A1 - #if XCHAL_HAVE_WINDOWED - s32e a0, sp, -12 /* for debug backtrace */ - #endif - rsr a0, PS /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_1 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_1 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - #if XCHAL_HAVE_WINDOWED - s32e a0, sp, -16 /* for debug backtrace */ - #endif - s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ - s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ - call0 _xt_context_save - - /* Save exc cause and vaddr into exception frame */ - rsr a0, EXCCAUSE - s32i a0, sp, XT_STK_EXCCAUSE - rsr a0, EXCVADDR - s32i a0, sp, XT_STK_EXCVADDR - - /* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM - #else - movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE - #endif - wsr a0, PS - - #ifdef XT_DEBUG_BACKTRACE - #ifndef __XTENSA_CALL0_ABI__ - rsr a0, EPC_1 /* return address for debug backtrace */ - movi a5, 0xC0000000 /* constant with top 2 bits set (call size) */ - rsync /* wait for WSR.PS to complete */ - or a0, a0, a5 /* set top 2 bits */ - addx2 a0, a5, a0 /* clear top bit -- thus simulating call4 size */ - #else - rsync /* wait for WSR.PS to complete */ - #endif - #endif - - rsr a2, EXCCAUSE /* recover exc cause */ - - #ifdef XT_INTEXC_HOOKS - /* - Call exception hook to pre-handle exceptions (if installed). - Pass EXCCAUSE in a2, and check result in a2 (if -1, skip default handling). - */ - movi a4, _xt_intexc_hooks - l32i a4, a4, 0 /* user exception hook index 0 */ - beqz a4, 1f -.Ln_xt_user_exc_call_hook: - #ifdef __XTENSA_CALL0_ABI__ - callx0 a4 - beqi a2, -1, .L_xt_user_done - #else - mov a6, a2 - callx4 a4 - beqi a6, -1, .L_xt_user_done - mov a2, a6 - #endif -1: - #endif - - rsr a2, EXCCAUSE /* recover exc cause */ - movi a3, _xt_exception_table - addx4 a4, a2, a3 /* a4 = address of exception table entry */ - l32i a4, a4, 0 /* a4 = handler address */ - #ifdef __XTENSA_CALL0_ABI__ - mov a2, sp /* a2 = pointer to exc frame */ - callx0 a4 /* call handler */ - #else - mov a6, sp /* a6 = pointer to exc frame */ - callx4 a4 /* call handler */ - #endif - -.L_xt_user_done: - - /* Restore context and return */ - call0 _xt_context_restore - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, PS - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_1 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove exception frame */ - rsync /* ensure PS and EPC written */ - rfe /* PS.EXCM is cleared */ - - -/* --------------------------------------------------------------------------------- - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. --------------------------------------------------------------------------------- -*/ - - .global _xt_user_exit - .type _xt_user_exit,@function - .align 4 -_xt_user_exit: - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, PS - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_1 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure PS and EPC written */ - rfe /* PS.EXCM is cleared */ - - -/* --------------------------------------------------------------------------------- -Syscall Exception Handler (jumped to from User Exception Handler). -Syscall 0 is required to spill the register windows (no-op in Call 0 ABI). -Only syscall 0 is handled here. Other syscalls return -1 to caller in a2. --------------------------------------------------------------------------------- -*/ - - .text - .type _xt_syscall_exc,@function - .align 4 -_xt_syscall_exc: - - #ifdef __XTENSA_CALL0_ABI__ - /* - Save minimal regs for scratch. Syscall 0 does nothing in Call0 ABI. - Use a minimal stack frame (16B) to save A2 & A3 for scratch. - PS.EXCM could be cleared here, but unlikely to improve worst-case latency. - rsr a0, PS - addi a0, a0, -PS_EXCM_MASK - wsr a0, PS - */ - addi sp, sp, -16 - s32i a2, sp, 8 - s32i a3, sp, 12 - #else /* Windowed ABI */ - /* - Save necessary context and spill the register windows. - PS.EXCM is still set and must remain set until after the spill. - Reuse context save function though it saves more than necessary. - For this reason, a full interrupt stack frame is allocated. - */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ - s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ - call0 _xt_context_save - #endif - - /* - Grab the interruptee's PC and skip over the 'syscall' instruction. - If it's at the end of a zero-overhead loop and it's not on the last - iteration, decrement loop counter and skip to beginning of loop. - */ - rsr a2, EPC_1 /* a2 = PC of 'syscall' */ - addi a3, a2, 3 /* ++PC */ - #if XCHAL_HAVE_LOOPS - rsr a0, LEND /* if (PC == LEND */ - bne a3, a0, 1f - rsr a0, LCOUNT /* && LCOUNT != 0) */ - beqz a0, 1f /* { */ - addi a0, a0, -1 /* --LCOUNT */ - rsr a3, LBEG /* PC = LBEG */ - wsr a0, LCOUNT /* } */ - #endif -1: wsr a3, EPC_1 /* update PC */ - - /* Restore interruptee's context and return from exception. */ - #ifdef __XTENSA_CALL0_ABI__ - l32i a2, sp, 8 - l32i a3, sp, 12 - addi sp, sp, 16 - #else - call0 _xt_context_restore - addi sp, sp, XT_STK_FRMSZ - #endif - movi a0, -1 - movnez a2, a0, a2 /* return -1 if not syscall 0 */ - rsr a0, EXCSAVE_1 - rfe - -/* --------------------------------------------------------------------------------- -Co-Processor Exception Handler (jumped to from User Exception Handler). -These exceptions are generated by co-processor instructions, which are only -allowed in thread code (not in interrupts or kernel code). This restriction is -deliberately imposed to reduce the burden of state-save/restore in interrupts. --------------------------------------------------------------------------------- -*/ -#if XCHAL_CP_NUM > 0 - - .section .rodata, "a" - -/* Offset to CP n save area in thread's CP save area. */ - .global _xt_coproc_sa_offset - .type _xt_coproc_sa_offset,@object - .align 16 /* minimize crossing cache boundaries */ -_xt_coproc_sa_offset: - .word XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA - .word XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA - -/* Bitmask for CP n's CPENABLE bit. */ - .type _xt_coproc_mask,@object - .align 16,,8 /* try to keep it all in one cache line */ - .set i, 0 -_xt_coproc_mask: - .rept XCHAL_CP_MAX - .long (i<<16) | (1<= 2 - - .begin literal_prefix .Level2InterruptVector - .section .Level2InterruptVector.text, "ax" - .global _Level2Vector - .type _Level2Vector,@function - .align 4 -_Level2Vector: - wsr a0, EXCSAVE_2 /* preserve a0 */ - call0 _xt_medint2 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_medint2,@function - .align 4 -_xt_medint2: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_2 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_2 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_2 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint2_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(2) | PS_UM - #else - movi a0, PS_INTLEVEL(2) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint2_exit - .type _xt_medint2_exit,@function - .align 4 -_xt_medint2_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_2 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_2 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 2 - -#endif /* Level 2 */ - -#if XCHAL_EXCM_LEVEL >= 3 - - .begin literal_prefix .Level3InterruptVector - .section .Level3InterruptVector.text, "ax" - .global _Level3Vector - .type _Level3Vector,@function - .align 4 -_Level3Vector: - wsr a0, EXCSAVE_3 /* preserve a0 */ - call0 _xt_medint3 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_medint3,@function - .align 4 -_xt_medint3: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_3 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_3 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_3 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint3_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(3) | PS_UM - #else - movi a0, PS_INTLEVEL(3) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint3_exit - .type _xt_medint3_exit,@function - .align 4 -_xt_medint3_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_3 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_3 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 3 - -#endif /* Level 3 */ - -#if XCHAL_EXCM_LEVEL >= 4 - - .begin literal_prefix .Level4InterruptVector - .section .Level4InterruptVector.text, "ax" - .global _Level4Vector - .type _Level4Vector,@function - .align 4 -_Level4Vector: - wsr a0, EXCSAVE_4 /* preserve a0 */ - call0 _xt_medint4 /* load interrupt handler */ - - .end literal_prefix - - .text - .type _xt_medint4,@function - .align 4 -_xt_medint4: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_4 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_4 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_4 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint4_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(4) | PS_UM - #else - movi a0, PS_INTLEVEL(4) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint4_exit - .type _xt_medint4_exit,@function - .align 4 -_xt_medint4_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_4 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_4 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 4 - -#endif /* Level 4 */ - -#if XCHAL_EXCM_LEVEL >= 5 - - .begin literal_prefix .Level5InterruptVector - .section .Level5InterruptVector.text, "ax" - .global _Level5Vector - .type _Level5Vector,@function - .align 4 -_Level5Vector: - wsr a0, EXCSAVE_5 /* preserve a0 */ - call0 _xt_medint5 /* load interrupt handler */ - - .end literal_prefix - - .text - .type _xt_medint5,@function - .align 4 -_xt_medint5: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_5 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_5 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_5 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint5_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(5) | PS_UM - #else - movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint5_exit - .type _xt_medint5_exit,@function - .align 4 -_xt_medint5_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_5 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_5 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 5 - -#endif /* Level 5 */ - -#if XCHAL_EXCM_LEVEL >= 6 - - .begin literal_prefix .Level6InterruptVector - .section .Level6InterruptVector.text, "ax" - .global _Level6Vector - .type _Level6Vector,@function - .align 4 -_Level6Vector: - wsr a0, EXCSAVE_6 /* preserve a0 */ - call0 _xt_medint6 /* load interrupt handler */ - - .end literal_prefix - - .text - .type _xt_medint6,@function - .align 4 -_xt_medint6: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_6 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_6 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_6 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint6_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(6) | PS_UM - #else - movi a0, PS_INTLEVEL(6) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint6_exit - .type _xt_medint6_exit,@function - .align 4 -_xt_medint6_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_6 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_6 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 6 - -#endif /* Level 6 */ - - -/******************************************************************************* - -HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS - -High priority interrupts are by definition those with priorities greater -than XCHAL_EXCM_LEVEL. This includes non-maskable (NMI). High priority -interrupts cannot interact with the RTOS, that is they must save all regs -they use and not call any RTOS function. - -A further restriction imposed by the Xtensa windowed architecture is that -high priority interrupts must not modify the stack area even logically -"above" the top of the interrupted stack (they need to provide their -own stack or static save area). - -Cadence Design Systems recommends high priority interrupt handlers be coded in assembly -and used for purposes requiring very short service times. - -Here are templates for high priority (level 2+) interrupt vectors. -They assume only one interrupt per level to avoid the burden of identifying -which interrupts at this level are pending and enabled. This allows for -minimum latency and avoids having to save/restore a2 in addition to a0. -If more than one interrupt per high priority level is configured, this burden -is on the handler which in any case must provide a way to save and restore -registers it uses without touching the interrupted stack. - -Each vector goes at a predetermined location according to the Xtensa -hardware configuration, which is ensured by its placement in a special -section known to the Xtensa linker support package (LSP). It performs -the minimum necessary before jumping to the handler in the .text section. - -*******************************************************************************/ - -/* -Currently only shells for high priority interrupt handlers are provided -here. However a template and example can be found in the Cadence Design Systems tools -documentation: "Microprocessor Programmer's Guide". -*/ - -#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 - - .begin literal_prefix .Level2InterruptVector - .section .Level2InterruptVector.text, "ax" - .global _Level2Vector - .type _Level2Vector,@function - .align 4 -_Level2Vector: - wsr a0, EXCSAVE_2 /* preserve a0 */ - call0 _xt_highint2 /* load interrupt handler */ - - .end literal_prefix - - .text - .type _xt_highint2,@function - .align 4 -_xt_highint2: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 2<<2 - beqz a0, 1f -.Ln_xt_highint2_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint2_exit: - rsr a0, EXCSAVE_2 /* restore a0 */ - rfi 2 - -#endif /* Level 2 */ - -#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 - - .begin literal_prefix .Level3InterruptVector - .section .Level3InterruptVector.text, "ax" - .global _Level3Vector - .type _Level3Vector,@function - .align 4 -_Level3Vector: - wsr a0, EXCSAVE_3 /* preserve a0 */ - call0 _xt_highint3 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_highint3,@function - .align 4 -_xt_highint3: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 3<<2 - beqz a0, 1f -.Ln_xt_highint3_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint3_exit: - rsr a0, EXCSAVE_3 /* restore a0 */ - rfi 3 - -#endif /* Level 3 */ - -#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 - - .begin literal_prefix .Level4InterruptVector - .section .Level4InterruptVector.text, "ax" - .global _Level4Vector - .type _Level4Vector,@function - .align 4 -_Level4Vector: - wsr a0, EXCSAVE_4 /* preserve a0 */ - call0 _xt_highint4 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_highint4,@function - .align 4 -_xt_highint4: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 4<<2 - beqz a0, 1f -.Ln_xt_highint4_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint4_exit: - rsr a0, EXCSAVE_4 /* restore a0 */ - rfi 4 - -#endif /* Level 4 */ - -#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 - - .begin literal_prefix .Level5InterruptVector - .section .Level5InterruptVector.text, "ax" - .global _Level5Vector - .type _Level5Vector,@function - .align 4 -_Level5Vector: - wsr a0, EXCSAVE_5 /* preserve a0 */ - call0 _xt_highint5 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_highint5,@function - .align 4 -_xt_highint5: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 5<<2 - beqz a0, 1f -.Ln_xt_highint5_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint5_exit: - rsr a0, EXCSAVE_5 /* restore a0 */ - rfi 5 - -#endif /* Level 5 */ - -#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 - - .begin literal_prefix .Level6InterruptVector - .section .Level6InterruptVector.text, "ax" - .global _Level6Vector - .type _Level6Vector,@function - .align 4 -_Level6Vector: - wsr a0, EXCSAVE_6 /* preserve a0 */ - call0 _xt_highint6 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_highint6,@function - .align 4 -_xt_highint6: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 6<<2 - beqz a0, 1f -.Ln_xt_highint6_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint6_exit: - rsr a0, EXCSAVE_6 /* restore a0 */ - rfi 6 - -#endif /* Level 6 */ - -#if XCHAL_HAVE_NMI - - .begin literal_prefix .NMIExceptionVector - .section .NMIExceptionVector.text, "ax" - .global _NMIExceptionVector - .type _NMIExceptionVector,@function - .align 4 -_NMIExceptionVector: - wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ - call0 _xt_nmi /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_nmi,@function - .align 4 -_xt_nmi: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, XCHAL_NMILEVEL<<2 - beqz a0, 1f -.Ln_xt_nmi_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE. - */ - - .align 4 -.L_xt_nmi_exit: - rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ - rfi XCHAL_NMILEVEL - -#endif /* NMI */ - - -/******************************************************************************* - -WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER - -Here is the code for each window overflow/underflow exception vector and -(interspersed) efficient code for handling the alloca exception cause. -Window exceptions are handled entirely in the vector area and are very -tight for performance. The alloca exception is also handled entirely in -the window vector area so comes at essentially no cost in code size. -Users should never need to modify them and Cadence Design Systems recommends -they do not. - -Window handlers go at predetermined vector locations according to the -Xtensa hardware configuration, which is ensured by their placement in a -special section known to the Xtensa linker support package (LSP). Since -their offsets in that section are always the same, the LSPs do not define -a section per vector. - -These things are coded for XEA2 only (XEA1 is not supported). - -Note on Underflow Handlers: -The underflow handler for returning from call[i+1] to call[i] -must preserve all the registers from call[i+1]'s window. -In particular, a0 and a1 must be preserved because the RETW instruction -will be reexecuted (and may even underflow if an intervening exception -has flushed call[i]'s registers). -Registers a2 and up may contain return values. - -*******************************************************************************/ - -#if XCHAL_HAVE_WINDOWED - - .section .WindowVectors.text, "ax" - -/* --------------------------------------------------------------------------------- -Window Overflow Exception for Call4. - -Invoked if a call[i] referenced a register (a4-a15) -that contains data from ancestor call[j]; -call[j] had done a call4 to call[j+1]. -On entry here: - window rotated to call[j] start point; - a0-a3 are registers to be saved; - a4-a15 must be preserved; - a5 is call[j+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x0 - .global _WindowOverflow4 -_WindowOverflow4: - - s32e a0, a5, -16 /* save a0 to call[j+1]'s stack frame */ - s32e a1, a5, -12 /* save a1 to call[j+1]'s stack frame */ - s32e a2, a5, -8 /* save a2 to call[j+1]'s stack frame */ - s32e a3, a5, -4 /* save a3 to call[j+1]'s stack frame */ - rfwo /* rotates back to call[i] position */ - -/* --------------------------------------------------------------------------------- -Window Underflow Exception for Call4 - -Invoked by RETW returning from call[i+1] to call[i] -where call[i]'s registers must be reloaded (not live in ARs); -where call[i] had done a call4 to call[i+1]. -On entry here: - window rotated to call[i] start point; - a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; - a4-a15 must be preserved (they are call[i+1].reg[0..11]); - a5 is call[i+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x40 - .global _WindowUnderflow4 -_WindowUnderflow4: - - l32e a0, a5, -16 /* restore a0 from call[i+1]'s stack frame */ - l32e a1, a5, -12 /* restore a1 from call[i+1]'s stack frame */ - l32e a2, a5, -8 /* restore a2 from call[i+1]'s stack frame */ - l32e a3, a5, -4 /* restore a3 from call[i+1]'s stack frame */ - rfwu - -/* --------------------------------------------------------------------------------- -Handle alloca exception generated by interruptee executing 'movsp'. -This uses space between the window vectors, so is essentially "free". -All interruptee's regs are intact except a0 which is saved in EXCSAVE_1, -and PS.EXCM has been set by the exception hardware (can't be interrupted). -The fact the alloca exception was taken means the registers associated with -the base-save area have been spilled and will be restored by the underflow -handler, so those 4 registers are available for scratch. -The code is optimized to avoid unaligned branches and minimize cache misses. --------------------------------------------------------------------------------- -*/ - - .align 4 - .global _xt_alloca_exc -_xt_alloca_exc: - - rsr a0, WINDOWBASE /* grab WINDOWBASE before rotw changes it */ - rotw -1 /* WINDOWBASE goes to a4, new a0-a3 are scratch */ - rsr a2, PS - extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS - xor a3, a3, a4 /* bits changed from old to current windowbase */ - rsr a4, EXCSAVE_1 /* restore original a0 (now in a4) */ - slli a3, a3, XCHAL_PS_OWB_SHIFT - xor a2, a2, a3 /* flip changed bits in old window base */ - wsr a2, PS /* update PS.OWB to new window base */ - rsync - - _bbci.l a4, 31, _WindowUnderflow4 - rotw -1 /* original a0 goes to a8 */ - _bbci.l a8, 30, _WindowUnderflow8 - rotw -1 - j _WindowUnderflow12 - -/* --------------------------------------------------------------------------------- -Window Overflow Exception for Call8 - -Invoked if a call[i] referenced a register (a4-a15) -that contains data from ancestor call[j]; -call[j] had done a call8 to call[j+1]. -On entry here: - window rotated to call[j] start point; - a0-a7 are registers to be saved; - a8-a15 must be preserved; - a9 is call[j+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x80 - .global _WindowOverflow8 -_WindowOverflow8: - - s32e a0, a9, -16 /* save a0 to call[j+1]'s stack frame */ - l32e a0, a1, -12 /* a0 <- call[j-1]'s sp - (used to find end of call[j]'s frame) */ - s32e a1, a9, -12 /* save a1 to call[j+1]'s stack frame */ - s32e a2, a9, -8 /* save a2 to call[j+1]'s stack frame */ - s32e a3, a9, -4 /* save a3 to call[j+1]'s stack frame */ - s32e a4, a0, -32 /* save a4 to call[j]'s stack frame */ - s32e a5, a0, -28 /* save a5 to call[j]'s stack frame */ - s32e a6, a0, -24 /* save a6 to call[j]'s stack frame */ - s32e a7, a0, -20 /* save a7 to call[j]'s stack frame */ - rfwo /* rotates back to call[i] position */ - -/* --------------------------------------------------------------------------------- -Window Underflow Exception for Call8 - -Invoked by RETW returning from call[i+1] to call[i] -where call[i]'s registers must be reloaded (not live in ARs); -where call[i] had done a call8 to call[i+1]. -On entry here: - window rotated to call[i] start point; - a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; - a8-a15 must be preserved (they are call[i+1].reg[0..7]); - a9 is call[i+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0xC0 - .global _WindowUnderflow8 -_WindowUnderflow8: - - l32e a0, a9, -16 /* restore a0 from call[i+1]'s stack frame */ - l32e a1, a9, -12 /* restore a1 from call[i+1]'s stack frame */ - l32e a2, a9, -8 /* restore a2 from call[i+1]'s stack frame */ - l32e a7, a1, -12 /* a7 <- call[i-1]'s sp - (used to find end of call[i]'s frame) */ - l32e a3, a9, -4 /* restore a3 from call[i+1]'s stack frame */ - l32e a4, a7, -32 /* restore a4 from call[i]'s stack frame */ - l32e a5, a7, -28 /* restore a5 from call[i]'s stack frame */ - l32e a6, a7, -24 /* restore a6 from call[i]'s stack frame */ - l32e a7, a7, -20 /* restore a7 from call[i]'s stack frame */ - rfwu - -/* --------------------------------------------------------------------------------- -Window Overflow Exception for Call12 - -Invoked if a call[i] referenced a register (a4-a15) -that contains data from ancestor call[j]; -call[j] had done a call12 to call[j+1]. -On entry here: - window rotated to call[j] start point; - a0-a11 are registers to be saved; - a12-a15 must be preserved; - a13 is call[j+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x100 - .global _WindowOverflow12 -_WindowOverflow12: - - s32e a0, a13, -16 /* save a0 to call[j+1]'s stack frame */ - l32e a0, a1, -12 /* a0 <- call[j-1]'s sp - (used to find end of call[j]'s frame) */ - s32e a1, a13, -12 /* save a1 to call[j+1]'s stack frame */ - s32e a2, a13, -8 /* save a2 to call[j+1]'s stack frame */ - s32e a3, a13, -4 /* save a3 to call[j+1]'s stack frame */ - s32e a4, a0, -48 /* save a4 to end of call[j]'s stack frame */ - s32e a5, a0, -44 /* save a5 to end of call[j]'s stack frame */ - s32e a6, a0, -40 /* save a6 to end of call[j]'s stack frame */ - s32e a7, a0, -36 /* save a7 to end of call[j]'s stack frame */ - s32e a8, a0, -32 /* save a8 to end of call[j]'s stack frame */ - s32e a9, a0, -28 /* save a9 to end of call[j]'s stack frame */ - s32e a10, a0, -24 /* save a10 to end of call[j]'s stack frame */ - s32e a11, a0, -20 /* save a11 to end of call[j]'s stack frame */ - rfwo /* rotates back to call[i] position */ - -/* --------------------------------------------------------------------------------- -Window Underflow Exception for Call12 - -Invoked by RETW returning from call[i+1] to call[i] -where call[i]'s registers must be reloaded (not live in ARs); -where call[i] had done a call12 to call[i+1]. -On entry here: - window rotated to call[i] start point; - a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; - a12-a15 must be preserved (they are call[i+1].reg[0..3]); - a13 is call[i+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x140 - .global _WindowUnderflow12 -_WindowUnderflow12: - - l32e a0, a13, -16 /* restore a0 from call[i+1]'s stack frame */ - l32e a1, a13, -12 /* restore a1 from call[i+1]'s stack frame */ - l32e a2, a13, -8 /* restore a2 from call[i+1]'s stack frame */ - l32e a11, a1, -12 /* a11 <- call[i-1]'s sp - (used to find end of call[i]'s frame) */ - l32e a3, a13, -4 /* restore a3 from call[i+1]'s stack frame */ - l32e a4, a11, -48 /* restore a4 from end of call[i]'s stack frame */ - l32e a5, a11, -44 /* restore a5 from end of call[i]'s stack frame */ - l32e a6, a11, -40 /* restore a6 from end of call[i]'s stack frame */ - l32e a7, a11, -36 /* restore a7 from end of call[i]'s stack frame */ - l32e a8, a11, -32 /* restore a8 from end of call[i]'s stack frame */ - l32e a9, a11, -28 /* restore a9 from end of call[i]'s stack frame */ - l32e a10, a11, -24 /* restore a10 from end of call[i]'s stack frame */ - l32e a11, a11, -20 /* restore a11 from end of call[i]'s stack frame */ - rfwu - -#endif /* XCHAL_HAVE_WINDOWED */ - - .section .UserEnter.text, "ax" - .global call_user_start - .type call_user_start,@function - .align 4 - .literal_position - - -call_user_start: - - movi a2, 0x40040000 /* note: absolute symbol, not a ptr */ - wsr a2, vecbase - call0 user_start /* user exception handler */ diff --git a/components/freertos/xtensa_vectors.S-old b/components/freertos/xtensa_vectors.S-old deleted file mode 100644 index 2d0f7a99d2..0000000000 --- a/components/freertos/xtensa_vectors.S-old +++ /dev/null @@ -1,2064 +0,0 @@ -/******************************************************************************* -Copyright (c) 2006-2015 Cadence Design Systems Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------- - - XTENSA VECTORS AND LOW LEVEL HANDLERS FOR AN RTOS - - Xtensa low level exception and interrupt vectors and handlers for an RTOS. - - Interrupt handlers and user exception handlers support interaction with - the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT before and - after user's specific interrupt handlers. These macros are defined in - xtensa_.h to call suitable functions in a specific RTOS. - - Users can install application-specific interrupt handlers for low and - medium level interrupts, by calling xt_set_interrupt_handler(). These - handlers can be written in C, and must obey C calling convention. The - handler table is indexed by the interrupt number. Each handler may be - provided with an argument. - - Note that the system timer interrupt is handled specially, and is - dispatched to the RTOS-specific handler. This timer cannot be hooked - by application code. - - Optional hooks are also provided to install a handler per level at - run-time, made available by compiling this source file with - '-DXT_INTEXC_HOOKS' (useful for automated testing). - -!! This file is a template that usually needs to be modified to handle !! -!! application specific interrupts. Search USER_EDIT for helpful comments !! -!! on where to insert handlers and how to write them. !! - - Users can also install application-specific exception handlers in the - same way, by calling xt_set_exception_handler(). One handler slot is - provided for each exception type. Note that some exceptions are handled - by the porting layer itself, and cannot be taken over by application - code in this manner. These are the alloca, syscall, and coprocessor - exceptions. - - The exception handlers can be written in C, and must follow C calling - convention. Each handler is passed a pointer to an exception frame as - its single argument. The exception frame is created on the stack, and - holds the saved context of the thread that took the exception. If the - handler returns, the context will be restored and the instruction that - caused the exception will be retried. If the handler makes any changes - to the saved state in the exception frame, the changes will be applied - when restoring the context. - - Because Xtensa is a configurable architecture, this port supports all user - generated configurations (except restrictions stated in the release notes). - This is accomplished by conditional compilation using macros and functions - defined in the Xtensa HAL (hardware adaptation layer) for your configuration. - Only the relevant parts of this file will be included in your RTOS build. - For example, this file provides interrupt vector templates for all types and - all priority levels, but only the ones in your configuration are built. - - NOTES on the use of 'call0' for long jumps instead of 'j': - 1. This file should be assembled with the -mlongcalls option to xt-xcc. - 2. The -mlongcalls compiler option causes 'call0 dest' to be expanded to - a sequence 'l32r a0, dest' 'callx0 a0' which works regardless of the - distance from the call to the destination. The linker then relaxes - it back to 'call0 dest' if it determines that dest is within range. - This allows more flexibility in locating code without the performance - overhead of the 'l32r' literal data load in cases where the destination - is in range of 'call0'. There is an additional benefit in that 'call0' - has a longer range than 'j' due to the target being word-aligned, so - the 'l32r' sequence is less likely needed. - 3. The use of 'call0' with -mlongcalls requires that register a0 not be - live at the time of the call, which is always the case for a function - call but needs to be ensured if 'call0' is used as a jump in lieu of 'j'. - 4. This use of 'call0' is independent of the C function call ABI. - -*******************************************************************************/ - -#include "xtensa_rtos.h" - - -/* Enable stack backtrace across exception/interrupt - see below */ -#define XT_DEBUG_BACKTRACE 0 - - -/* --------------------------------------------------------------------------------- - Defines used to access _xtos_interrupt_table. --------------------------------------------------------------------------------- -*/ -#define XIE_HANDLER 0 -#define XIE_ARG 4 -#define XIE_SIZE 8 - -/* --------------------------------------------------------------------------------- - Macro extract_msb - return the input with only the highest bit set. - - Input : "ain" - Input value, clobbered. - Output : "aout" - Output value, has only one bit set, MSB of "ain". - The two arguments must be different AR registers. --------------------------------------------------------------------------------- -*/ - - .macro extract_msb aout ain -1: - addi \aout, \ain, -1 /* aout = ain - 1 */ - and \ain, \ain, \aout /* ain = ain & aout */ - bnez \ain, 1b /* repeat until ain == 0 */ - addi \aout, \aout, 1 /* return aout + 1 */ - .endm - -/* --------------------------------------------------------------------------------- - Macro dispatch_c_isr - dispatch interrupts to user ISRs. - This will dispatch to user handlers (if any) that are registered in the - XTOS dispatch table (_xtos_interrupt_table). These handlers would have - been registered by calling _xtos_set_interrupt_handler(). There is one - exception - the timer interrupt used by the OS will not be dispatched - to a user handler - this must be handled by the caller of this macro. - - Level triggered and software interrupts are automatically deasserted by - this code. - - ASSUMPTIONS: - -- PS.INTLEVEL is set to "level" at entry - -- PS.EXCM = 0, C calling enabled - - NOTE: For CALL0 ABI, a12-a15 have not yet been saved. - - NOTE: This macro will use registers a0 and a2-a6. The arguments are: - level -- interrupt level - mask -- interrupt bitmask for this level --------------------------------------------------------------------------------- -*/ - - .macro dispatch_c_isr level mask - - /* Get mask of pending, enabled interrupts at this level into a2. */ - -.L_xt_user_int_&level&: - rsr a2, INTENABLE - rsr a3, INTERRUPT - movi a4, \mask - and a2, a2, a3 - and a2, a2, a4 - beqz a2, 9f /* nothing to do */ - - /* This bit of code provides a nice debug backtrace in the debugger. - It does take a few more instructions, so undef XT_DEBUG_BACKTRACE - if you want to save the cycles. - */ - #if XT_DEBUG_BACKTRACE - #ifndef __XTENSA_CALL0_ABI__ - rsr a0, EPC_1 + \level - 1 /* return address */ - movi a4, 0xC0000000 /* constant with top 2 bits set (call size) */ - or a0, a0, a4 /* set top 2 bits */ - addx2 a0, a4, a0 /* clear top bit -- simulating call4 size */ - #endif - #endif - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a4, _xt_intexc_hooks - l32i a4, a4, \level << 2 - beqz a4, 2f - #ifdef __XTENSA_CALL0_ABI__ - callx0 a4 - beqz a2, 9f - #else - mov a6, a2 - callx4 a4 - beqz a6, 9f - mov a2, a6 - #endif -2: - #endif - - /* Now look up in the dispatch table and call user ISR if any. */ - /* If multiple bits are set then MSB has highest priority. */ - - extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */ - - #ifdef XT_USE_SWPRI - /* Enable all interrupts at this level that are numerically higher - than the one we just selected, since they are treated as higher - priority. - */ - movi a3, \mask /* a3 = all interrupts at this level */ - add a2, a4, a4 /* a2 = a4 << 1 */ - addi a2, a2, -1 /* a2 = mask of 1's <= a4 bit */ - and a2, a2, a3 /* a2 = mask of all bits <= a4 at this level */ - movi a3, _xt_intdata - l32i a6, a3, 4 /* a6 = _xt_vpri_mask */ - neg a2, a2 - addi a2, a2, -1 /* a2 = mask to apply */ - and a5, a6, a2 /* mask off all bits <= a4 bit */ - s32i a5, a3, 4 /* update _xt_vpri_mask */ - rsr a3, INTENABLE - and a3, a3, a2 /* mask off all bits <= a4 bit */ - wsr a3, INTENABLE - rsil a3, \level - 1 /* lower interrupt level by 1 */ - #endif - - movi a3, XT_TIMER_INTEN /* a3 = timer interrupt bit */ - wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */ - beq a3, a4, 7f /* if timer interrupt then skip table */ - - find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */ - - movi a4, _xt_interrupt_table - addx8 a3, a3, a4 /* a3 = address of interrupt table entry */ - l32i a4, a3, XIE_HANDLER /* a4 = handler address */ - #ifdef __XTENSA_CALL0_ABI__ - mov a12, a6 /* save in callee-saved reg */ - l32i a2, a3, XIE_ARG /* a2 = handler arg */ - callx0 a4 /* call handler */ - mov a2, a12 - #else - mov a2, a6 /* save in windowed reg */ - l32i a6, a3, XIE_ARG /* a6 = handler arg */ - callx4 a4 /* call handler */ - #endif - - #ifdef XT_USE_SWPRI - j 8f - #else - j .L_xt_user_int_&level& /* check for more interrupts */ - #endif - -7: - - .ifeq XT_TIMER_INTPRI - \level -.L_xt_user_int_timer_&level&: - /* - Interrupt handler for the RTOS tick timer if at this level. - We'll be reading the interrupt state again after this call - so no need to preserve any registers except a6 (vpri_mask). - */ - - #ifdef __XTENSA_CALL0_ABI__ - mov a12, a6 - call0 XT_RTOS_TIMER_INT - mov a2, a12 - #else - mov a2, a6 - call4 XT_RTOS_TIMER_INT - #endif - .endif - - #ifdef XT_USE_SWPRI - j 8f - #else - j .L_xt_user_int_&level& /* check for more interrupts */ - #endif - - #ifdef XT_USE_SWPRI -8: - /* Restore old value of _xt_vpri_mask from a2. Also update INTENABLE from - virtual _xt_intenable which _could_ have changed during interrupt - processing. */ - - movi a3, _xt_intdata - l32i a4, a3, 0 /* a4 = _xt_intenable */ - s32i a2, a3, 4 /* update _xt_vpri_mask */ - and a4, a4, a2 /* a4 = masked intenable */ - wsr a4, INTENABLE /* update INTENABLE */ - #endif - -9: - /* done */ - - .endm - - -/* --------------------------------------------------------------------------------- - Panic handler. - Should be reached by call0 (preferable) or jump only. If call0, a0 says where - from. If on simulator, display panic message and abort, else loop indefinitely. --------------------------------------------------------------------------------- -*/ - - .text - .global panicHandlerRegs - .global panicHandler - .global panicStack - - .global _xt_panic - .type _xt_panic,@function - .align 4 - -_xt_panic: - //ToDo: save registers - movi a2, panicHandlerRegs - s32i a0,a2,0 - s32i a1,a2,4 - s32i a2,a2,8 - s32i a3,a2,12 - s32i a4,a2,16 - s32i a5,a2,20 - s32i a6,a2,24 - s32i a7,a2,28 - s32i a8,a2,32 - s32i a9,a2,36 - s32i a10,a2,40 - s32i a11,a2,44 - s32i a12,a2,48 - s32i a13,a2,52 - s32i a14,a2,56 - s32i a15,a2,60 - - rsr a3, EXCSAVE - s32i a3,a2,64 - rsr a3, EXCSAVE+1 - s32i a3,a2,68 - rsr a3, EXCSAVE+2 - s32i a3,a2,72 - rsr a3, EXCSAVE+3 - s32i a3,a2,76 - rsr a3, EXCSAVE+4 - s32i a3,a2,80 - rsr a3, EXCSAVE+5 - s32i a3,a2,84 - rsr a3, EXCSAVE+6 - s32i a3,a2,88 - rsr a3, EXCSAVE+7 - s32i a3,a2,92 - - rsr a3, EPC - s32i a3,a2,96 - rsr a3, EPC+1 - s32i a3,a2,100 - rsr a3, EPC+2 - s32i a3,a2,104 - rsr a3, EPC+3 - s32i a3,a2,108 - rsr a3, EPC+4 - s32i a3,a2,112 - rsr a3, EPC+5 - s32i a3,a2,116 - rsr a3, EPC+6 - s32i a3,a2,120 - rsr a3, EPC+7 - s32i a3,a2,124 - - rsr a3, DEPC - s32i a3,a2,128 - rsr a3, EXCVADDR - s32i a3,a2,132 - - //Reset window start / base to 0 - movi a2, 1 - wsr a2, windowstart - movi a2, 0 - wsr a2, windowbase - rsync - - //Clear EXCM, set WOE flags - rsr a2, ps - movi a3, ~(PS_EXCM_MASK) - and a2, a2, a3 - movi a3, PS_WOE_MASK - or a2, a2, a3 - wsr a2, ps - rsync - - //Switch to private stack - movi a1,panicStack+(255*4) - rsil a2, XCHAL_EXCM_LEVEL /* disable all low & med ints */ - - - // Debug: output '!' on serport - movi a2,0x60000000 - movi a3,'!' - s32i a3,a2,0 - - movi a3, panicHandlerRegs - l32i a2,a3,0 - call0 panic_print_hex - rsr a2, EXCCAUSE - call0 panic_print_hex - rsr a2, EXCVADDR - call0 panic_print_hex - rsr a2,EPC+1 - call0 panic_print_hex - rsr a2,EPC+2 - call0 panic_print_hex - rsr a2,EPC+3 - call0 panic_print_hex - rsr a2,EPC+6 - call0 panic_print_hex - rsr a2,EXCSAVE_1 - call0 panic_print_hex - rsr a2,DEPC - call0 panic_print_hex - - //Call panic handler -// movi a4, panicHandler -// callx4 a4 - call4 panicHandler - - movi a2,0x60000000 - movi a3,'d' - s32i a3,a2,0 - - -1: j 1b /* loop infinitely */ - - .align 4 -panicHandlerz: - entry a1,32 - movi a2,0x60000000 - movi a3,'h' - memw - s32i a3,a2,0 - - retw - - - .align 4 -//Call using call0. Prints the hex char in a2. Kills a3, a4, a5 -panic_print_hex: - movi a3,0x60000000 - movi a4,8 -panic_print_hex_loop: - l32i a5, a3, 0x1c - extui a5, a5, 16, 8 - bgei a5,64,panic_print_hex_loop - - srli a5,a2,28 - bgei a5,10,panic_print_hex_a - addi a5,a5,'0' - j panic_print_hex_ok -panic_print_hex_a: - addi a5,a5,'A'-10 -panic_print_hex_ok: - s32i a5,a3,0 - slli a2,a2,4 - - addi a4,a4,-1 - bnei a4,0,panic_print_hex_loop - movi a5,' ' - s32i a5,a3,0 - - ret - - - - .section .rodata, "a" - .align 4 - - - -/* --------------------------------------------------------------------------------- - Hooks to dynamically install handlers for exceptions and interrupts. - Allows automated regression frameworks to install handlers per test. - Consists of an array of function pointers indexed by interrupt level, - with index 0 containing the entry for user exceptions. - Initialized with all 0s, meaning no handler is installed at each level. - See comment in xtensa_rtos.h for more details. --------------------------------------------------------------------------------- -*/ - - #ifdef XT_INTEXC_HOOKS - .data - .global _xt_intexc_hooks - .type _xt_intexc_hooks,@object - .align 4 - -_xt_intexc_hooks: - .fill XT_INTEXC_HOOK_NUM, 4, 0 - #endif - - -/* --------------------------------------------------------------------------------- - EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS - (except window exception vectors). - - Each vector goes at a predetermined location according to the Xtensa - hardware configuration, which is ensured by its placement in a special - section known to the Xtensa linker support package (LSP). It performs - the minimum necessary before jumping to the handler in the .text section. - - The corresponding handler goes in the normal .text section. It sets up - the appropriate stack frame, saves a few vector-specific registers and - calls XT_RTOS_INT_ENTER to save the rest of the interrupted context - and enter the RTOS, then sets up a C environment. It then calls the - user's interrupt handler code (which may be coded in C) and finally - calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling. - - While XT_RTOS_INT_EXIT does not return directly to the interruptee, - eventually the RTOS scheduler will want to dispatch the interrupted - task or handler. The scheduler will return to the exit point that was - saved in the interrupt stack frame at XT_STK_EXIT. --------------------------------------------------------------------------------- -*/ - - -/* --------------------------------------------------------------------------------- -Debug Exception. --------------------------------------------------------------------------------- -*/ - -#if XCHAL_HAVE_DEBUG - - .begin literal_prefix .DebugExceptionVector - .section .DebugExceptionVector.text, "ax" - .global _DebugExceptionVector - .align 4 - -_DebugExceptionVector: - - #ifdef XT_SIMULATOR - /* - In the simulator, let the debugger (if any) handle the debug exception, - or simply stop the simulation: - */ - wsr a2, EXCSAVE+XCHAL_DEBUGLEVEL /* save a2 where sim expects it */ - movi a2, SYS_gdb_enter_sktloop - simcall /* have ISS handle debug exc. */ - #elif 0 /* change condition to 1 to use the HAL minimal debug handler */ - wsr a3, EXCSAVE+XCHAL_DEBUGLEVEL - movi a3, xthal_debugexc_defhndlr_nw /* use default debug handler */ - jx a3 - #else - wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */ - call0 _xt_panic /* does not return */ - rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */ - #endif - - .end literal_prefix - -#endif - -/* --------------------------------------------------------------------------------- -Double Exception. -Double exceptions are not a normal occurrence. They indicate a bug of some kind. --------------------------------------------------------------------------------- -*/ - -#ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR - - .begin literal_prefix .DoubleExceptionVector - .section .DoubleExceptionVector.text, "ax" - .global _DoubleExceptionVector - .align 4 - -_DoubleExceptionVector: - - #if XCHAL_HAVE_DEBUG - break 1, 4 /* unhandled double exception */ - #endif - call0 _xt_panic /* does not return */ - rfde /* make a0 point here not later */ - - .end literal_prefix - -#endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */ - -/* --------------------------------------------------------------------------------- -Kernel Exception (including Level 1 Interrupt from kernel mode). --------------------------------------------------------------------------------- -*/ - - .begin literal_prefix .KernelExceptionVector - .section .KernelExceptionVector.text, "ax" - .global _KernelExceptionVector - .align 4 - -_KernelExceptionVector: - - wsr a0, EXCSAVE_1 /* preserve a0 */ - call0 _xt_kernel_exc /* kernel exception handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .align 4 - -_xt_kernel_exc: - #if XCHAL_HAVE_DEBUG - break 1, 0 /* unhandled kernel exception */ - #endif - call0 _xt_panic /* does not return */ - rfe /* make a0 point here not there */ - - -/* --------------------------------------------------------------------------------- -User Exception (including Level 1 Interrupt from user mode). --------------------------------------------------------------------------------- -*/ - - .begin literal_prefix .UserExceptionVector - .section .UserExceptionVector.text, "ax" - .global _UserExceptionVector - .type _UserExceptionVector,@function - .align 4 - -_UserExceptionVector: - - wsr a0, EXCSAVE_1 /* preserve a0 */ - call0 _xt_user_exc /* user exception handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - -/* --------------------------------------------------------------------------------- - Insert some waypoints for jumping beyond the signed 8-bit range of - conditional branch instructions, so the conditional branchces to specific - exception handlers are not taken in the mainline. Saves some cycles in the - mainline. --------------------------------------------------------------------------------- -*/ - - .text - - #if XCHAL_HAVE_WINDOWED - .align 4 -_xt_to_alloca_exc: - call0 _xt_alloca_exc /* in window vectors section */ - /* never returns here - call0 is used as a jump (see note at top) */ - #endif - - .align 4 -_xt_to_syscall_exc: - call0 _xt_syscall_exc - /* never returns here - call0 is used as a jump (see note at top) */ - - #if XCHAL_CP_NUM > 0 - .align 4 -_xt_to_coproc_exc: - call0 _xt_coproc_exc - /* never returns here - call0 is used as a jump (see note at top) */ - #endif - - -/* --------------------------------------------------------------------------------- - User exception handler. --------------------------------------------------------------------------------- -*/ - - .type _xt_user_exc,@function - .align 4 - -_xt_user_exc: - - /* If level 1 interrupt then jump to the dispatcher */ - rsr a0, EXCCAUSE - beqi a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_lowint1 - - /* Handle any coprocessor exceptions. Rely on the fact that exception - numbers above EXCCAUSE_CP0_DISABLED all relate to the coprocessors. - */ - #if XCHAL_CP_NUM > 0 - bgeui a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc - #endif - - /* Handle alloca and syscall exceptions */ - #if XCHAL_HAVE_WINDOWED - beqi a0, EXCCAUSE_ALLOCA, _xt_to_alloca_exc - #endif - beqi a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc - - //HACK! No custom vector stuff, just call panic handler directly. ToDo: remove this when possible. -JD - call0 _xt_panic - - /* Handle all other exceptions. All can have user-defined handlers. */ - /* NOTE: we'll stay on the user stack for exception handling. */ - - /* Allocate exception frame and save minimal context. */ - mov a0, sp - addi sp, sp, -XT_STK_FRMSZ - s32i a0, sp, XT_STK_A1 - #if XCHAL_HAVE_WINDOWED - s32e a0, sp, -12 /* for debug backtrace */ - #endif - rsr a0, PS /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_1 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_1 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - #if XCHAL_HAVE_WINDOWED - s32e a0, sp, -16 /* for debug backtrace */ - #endif - s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ - s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ - call0 _xt_context_save - - /* Save exc cause and vaddr into exception frame */ - rsr a0, EXCCAUSE - s32i a0, sp, XT_STK_EXCCAUSE - rsr a0, EXCVADDR - s32i a0, sp, XT_STK_EXCVADDR - - /* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM - #else - movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE - #endif - wsr a0, PS - - #ifdef XT_DEBUG_BACKTRACE - #ifndef __XTENSA_CALL0_ABI__ - rsr a0, EPC_1 /* return address for debug backtrace */ - movi a5, 0xC0000000 /* constant with top 2 bits set (call size) */ - rsync /* wait for WSR.PS to complete */ - or a0, a0, a5 /* set top 2 bits */ - addx2 a0, a5, a0 /* clear top bit -- thus simulating call4 size */ - #else - rsync /* wait for WSR.PS to complete */ - #endif - #endif - - rsr a2, EXCCAUSE /* recover exc cause */ - - #ifdef XT_INTEXC_HOOKS - /* - Call exception hook to pre-handle exceptions (if installed). - Pass EXCCAUSE in a2, and check result in a2 (if -1, skip default handling). - */ - movi a4, _xt_intexc_hooks - l32i a4, a4, 0 /* user exception hook index 0 */ - beqz a4, 1f -.Ln_xt_user_exc_call_hook: - #ifdef __XTENSA_CALL0_ABI__ - callx0 a4 - beqi a2, -1, .L_xt_user_done - #else - mov a6, a2 - callx4 a4 - beqi a6, -1, .L_xt_user_done - mov a2, a6 - #endif -1: - #endif - - rsr a2, EXCCAUSE /* recover exc cause */ - movi a3, _xt_exception_table - addx4 a4, a2, a3 /* a4 = address of exception table entry */ - l32i a4, a4, 0 /* a4 = handler address */ - #ifdef __XTENSA_CALL0_ABI__ - mov a2, sp /* a2 = pointer to exc frame */ - callx0 a4 /* call handler */ - #else - mov a6, sp /* a6 = pointer to exc frame */ - callx4 a4 /* call handler */ - #endif - -.L_xt_user_done: - - /* Restore context and return */ - call0 _xt_context_restore - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, PS - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_1 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove exception frame */ - rsync /* ensure PS and EPC written */ - rfe /* PS.EXCM is cleared */ - - -/* --------------------------------------------------------------------------------- - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. --------------------------------------------------------------------------------- -*/ - - .global _xt_user_exit - .type _xt_user_exit,@function - .align 4 -_xt_user_exit: - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, PS - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_1 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure PS and EPC written */ - rfe /* PS.EXCM is cleared */ - - -/* --------------------------------------------------------------------------------- -Syscall Exception Handler (jumped to from User Exception Handler). -Syscall 0 is required to spill the register windows (no-op in Call 0 ABI). -Only syscall 0 is handled here. Other syscalls return -1 to caller in a2. --------------------------------------------------------------------------------- -*/ - - .text - .type _xt_syscall_exc,@function - .align 4 -_xt_syscall_exc: - - #ifdef __XTENSA_CALL0_ABI__ - /* - Save minimal regs for scratch. Syscall 0 does nothing in Call0 ABI. - Use a minimal stack frame (16B) to save A2 & A3 for scratch. - PS.EXCM could be cleared here, but unlikely to improve worst-case latency. - rsr a0, PS - addi a0, a0, -PS_EXCM_MASK - wsr a0, PS - */ - addi sp, sp, -16 - s32i a2, sp, 8 - s32i a3, sp, 12 - #else /* Windowed ABI */ - /* - Save necessary context and spill the register windows. - PS.EXCM is still set and must remain set until after the spill. - Reuse context save function though it saves more than necessary. - For this reason, a full interrupt stack frame is allocated. - */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ - s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ - call0 _xt_context_save - #endif - - /* - Grab the interruptee's PC and skip over the 'syscall' instruction. - If it's at the end of a zero-overhead loop and it's not on the last - iteration, decrement loop counter and skip to beginning of loop. - */ - rsr a2, EPC_1 /* a2 = PC of 'syscall' */ - addi a3, a2, 3 /* ++PC */ - #if XCHAL_HAVE_LOOPS - rsr a0, LEND /* if (PC == LEND */ - bne a3, a0, 1f - rsr a0, LCOUNT /* && LCOUNT != 0) */ - beqz a0, 1f /* { */ - addi a0, a0, -1 /* --LCOUNT */ - rsr a3, LBEG /* PC = LBEG */ - wsr a0, LCOUNT /* } */ - #endif -1: wsr a3, EPC_1 /* update PC */ - - /* Restore interruptee's context and return from exception. */ - #ifdef __XTENSA_CALL0_ABI__ - l32i a2, sp, 8 - l32i a3, sp, 12 - addi sp, sp, 16 - #else - call0 _xt_context_restore - addi sp, sp, XT_STK_FRMSZ - #endif - movi a0, -1 - movnez a2, a0, a2 /* return -1 if not syscall 0 */ - rsr a0, EXCSAVE_1 - rfe - -/* --------------------------------------------------------------------------------- -Co-Processor Exception Handler (jumped to from User Exception Handler). -These exceptions are generated by co-processor instructions, which are only -allowed in thread code (not in interrupts or kernel code). This restriction is -deliberately imposed to reduce the burden of state-save/restore in interrupts. --------------------------------------------------------------------------------- -*/ -#if XCHAL_CP_NUM > 0 - - .section .rodata, "a" - -/* Offset to CP n save area in thread's CP save area. */ - .global _xt_coproc_sa_offset - .type _xt_coproc_sa_offset,@object - .align 16 /* minimize crossing cache boundaries */ -_xt_coproc_sa_offset: - .word XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA - .word XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA - -/* Bitmask for CP n's CPENABLE bit. */ - .type _xt_coproc_mask,@object - .align 16,,8 /* try to keep it all in one cache line */ - .set i, 0 -_xt_coproc_mask: - .rept XCHAL_CP_MAX - .long (i<<16) | (1<= 2 - - .begin literal_prefix .Level2InterruptVector - .section .Level2InterruptVector.text, "ax" - .global _Level2Vector - .type _Level2Vector,@function - .align 4 -_Level2Vector: - wsr a0, EXCSAVE_2 /* preserve a0 */ - call0 _xt_medint2 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_medint2,@function - .align 4 -_xt_medint2: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_2 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_2 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_2 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint2_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(2) | PS_UM - #else - movi a0, PS_INTLEVEL(2) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint2_exit - .type _xt_medint2_exit,@function - .align 4 -_xt_medint2_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_2 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_2 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 2 - -#endif /* Level 2 */ - -#if XCHAL_EXCM_LEVEL >= 3 - - .begin literal_prefix .Level3InterruptVector - .section .Level3InterruptVector.text, "ax" - .global _Level3Vector - .type _Level3Vector,@function - .align 4 -_Level3Vector: - wsr a0, EXCSAVE_3 /* preserve a0 */ - call0 _xt_medint3 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_medint3,@function - .align 4 -_xt_medint3: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_3 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_3 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_3 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint3_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(3) | PS_UM - #else - movi a0, PS_INTLEVEL(3) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint3_exit - .type _xt_medint3_exit,@function - .align 4 -_xt_medint3_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_3 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_3 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 3 - -#endif /* Level 3 */ - -#if XCHAL_EXCM_LEVEL >= 4 - - .begin literal_prefix .Level4InterruptVector - .section .Level4InterruptVector.text, "ax" - .global _Level4Vector - .type _Level4Vector,@function - .align 4 -_Level4Vector: - wsr a0, EXCSAVE_4 /* preserve a0 */ - call0 _xt_medint4 /* load interrupt handler */ - - .end literal_prefix - - .text - .type _xt_medint4,@function - .align 4 -_xt_medint4: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_4 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_4 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_4 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint4_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(4) | PS_UM - #else - movi a0, PS_INTLEVEL(4) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint4_exit - .type _xt_medint4_exit,@function - .align 4 -_xt_medint4_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_4 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_4 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 4 - -#endif /* Level 4 */ - -#if XCHAL_EXCM_LEVEL >= 5 - - .begin literal_prefix .Level5InterruptVector - .section .Level5InterruptVector.text, "ax" - .global _Level5Vector - .type _Level5Vector,@function - .align 4 -_Level5Vector: - wsr a0, EXCSAVE_5 /* preserve a0 */ - call0 _xt_medint5 /* load interrupt handler */ - - .end literal_prefix - - .text - .type _xt_medint5,@function - .align 4 -_xt_medint5: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_5 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_5 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_5 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint5_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(5) | PS_UM - #else - movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint5_exit - .type _xt_medint5_exit,@function - .align 4 -_xt_medint5_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_5 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_5 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 5 - -#endif /* Level 5 */ - -#if XCHAL_EXCM_LEVEL >= 6 - - .begin literal_prefix .Level6InterruptVector - .section .Level6InterruptVector.text, "ax" - .global _Level6Vector - .type _Level6Vector,@function - .align 4 -_Level6Vector: - wsr a0, EXCSAVE_6 /* preserve a0 */ - call0 _xt_medint6 /* load interrupt handler */ - - .end literal_prefix - - .text - .type _xt_medint6,@function - .align 4 -_xt_medint6: - mov a0, sp /* sp == a1 */ - addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ - s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ - rsr a0, EPS_6 /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_6 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - rsr a0, EXCSAVE_6 /* save interruptee's a0 */ - s32i a0, sp, XT_STK_A0 - movi a0, _xt_medint6_exit /* save exit point for dispatch */ - s32i a0, sp, XT_STK_EXIT - - /* Save rest of interrupt context and enter RTOS. */ - call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ - - /* !! We are now on the RTOS system stack !! */ - - /* Set up PS for C, enable interrupts above this level and clear EXCM. */ - #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(6) | PS_UM - #else - movi a0, PS_INTLEVEL(6) | PS_UM | PS_WOE - #endif - wsr a0, PS - rsync - - /* OK to call C code at this point, dispatch user ISRs */ - - dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK - - /* Done handling interrupts, transfer control to OS */ - call0 XT_RTOS_INT_EXIT /* does not return directly here */ - - /* - Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT - on entry and used to return to a thread or interrupted interrupt handler. - */ - .global _xt_medint6_exit - .type _xt_medint6_exit,@function - .align 4 -_xt_medint6_exit: - /* Restore only level-specific regs (the rest were already restored) */ - l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ - wsr a0, EPS_6 - l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ - wsr a0, EPC_6 - l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ - l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ - rsync /* ensure EPS and EPC written */ - rfi 6 - -#endif /* Level 6 */ - - -/******************************************************************************* - -HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS - -High priority interrupts are by definition those with priorities greater -than XCHAL_EXCM_LEVEL. This includes non-maskable (NMI). High priority -interrupts cannot interact with the RTOS, that is they must save all regs -they use and not call any RTOS function. - -A further restriction imposed by the Xtensa windowed architecture is that -high priority interrupts must not modify the stack area even logically -"above" the top of the interrupted stack (they need to provide their -own stack or static save area). - -Cadence Design Systems recommends high priority interrupt handlers be coded in assembly -and used for purposes requiring very short service times. - -Here are templates for high priority (level 2+) interrupt vectors. -They assume only one interrupt per level to avoid the burden of identifying -which interrupts at this level are pending and enabled. This allows for -minimum latency and avoids having to save/restore a2 in addition to a0. -If more than one interrupt per high priority level is configured, this burden -is on the handler which in any case must provide a way to save and restore -registers it uses without touching the interrupted stack. - -Each vector goes at a predetermined location according to the Xtensa -hardware configuration, which is ensured by its placement in a special -section known to the Xtensa linker support package (LSP). It performs -the minimum necessary before jumping to the handler in the .text section. - -*******************************************************************************/ - -/* -Currently only shells for high priority interrupt handlers are provided -here. However a template and example can be found in the Cadence Design Systems tools -documentation: "Microprocessor Programmer's Guide". -*/ - -#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 - - .begin literal_prefix .Level2InterruptVector - .section .Level2InterruptVector.text, "ax" - .global _Level2Vector - .type _Level2Vector,@function - .align 4 -_Level2Vector: - wsr a0, EXCSAVE_2 /* preserve a0 */ - call0 _xt_highint2 /* load interrupt handler */ - - .end literal_prefix - - .text - .type _xt_highint2,@function - .align 4 -_xt_highint2: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 2<<2 - beqz a0, 1f -.Ln_xt_highint2_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint2_exit: - rsr a0, EXCSAVE_2 /* restore a0 */ - rfi 2 - -#endif /* Level 2 */ - -#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 - - .begin literal_prefix .Level3InterruptVector - .section .Level3InterruptVector.text, "ax" - .global _Level3Vector - .type _Level3Vector,@function - .align 4 -_Level3Vector: - wsr a0, EXCSAVE_3 /* preserve a0 */ - call0 _xt_highint3 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_highint3,@function - .align 4 -_xt_highint3: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 3<<2 - beqz a0, 1f -.Ln_xt_highint3_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint3_exit: - rsr a0, EXCSAVE_3 /* restore a0 */ - rfi 3 - -#endif /* Level 3 */ - -#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 - - .begin literal_prefix .Level4InterruptVector - .section .Level4InterruptVector.text, "ax" - .global _Level4Vector - .type _Level4Vector,@function - .align 4 -_Level4Vector: - wsr a0, EXCSAVE_4 /* preserve a0 */ - call0 _xt_highint4 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_highint4,@function - .align 4 -_xt_highint4: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 4<<2 - beqz a0, 1f -.Ln_xt_highint4_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint4_exit: - rsr a0, EXCSAVE_4 /* restore a0 */ - rfi 4 - -#endif /* Level 4 */ - -#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 - - .begin literal_prefix .Level5InterruptVector - .section .Level5InterruptVector.text, "ax" - .global _Level5Vector - .type _Level5Vector,@function - .align 4 -_Level5Vector: - wsr a0, EXCSAVE_5 /* preserve a0 */ - call0 _xt_highint5 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_highint5,@function - .align 4 -_xt_highint5: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 5<<2 - beqz a0, 1f -.Ln_xt_highint5_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint5_exit: - rsr a0, EXCSAVE_5 /* restore a0 */ - rfi 5 - -#endif /* Level 5 */ - -#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 - - .begin literal_prefix .Level6InterruptVector - .section .Level6InterruptVector.text, "ax" - .global _Level6Vector - .type _Level6Vector,@function - .align 4 -_Level6Vector: - wsr a0, EXCSAVE_6 /* preserve a0 */ - call0 _xt_highint6 /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_highint6,@function - .align 4 -_xt_highint6: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 6<<2 - beqz a0, 1f -.Ln_xt_highint6_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint6_exit: - rsr a0, EXCSAVE_6 /* restore a0 */ - rfi 6 - -#endif /* Level 6 */ - -#if XCHAL_HAVE_NMI - - .begin literal_prefix .NMIExceptionVector - .section .NMIExceptionVector.text, "ax" - .global _NMIExceptionVector - .type _NMIExceptionVector,@function - .align 4 -_NMIExceptionVector: - wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ - call0 _xt_nmi /* load interrupt handler */ - /* never returns here - call0 is used as a jump (see note at top) */ - - .end literal_prefix - - .text - .type _xt_nmi,@function - .align 4 -_xt_nmi: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, XCHAL_NMILEVEL<<2 - beqz a0, 1f -.Ln_xt_nmi_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE. - */ - - .align 4 -.L_xt_nmi_exit: - rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ - rfi XCHAL_NMILEVEL - -#endif /* NMI */ - - -/******************************************************************************* - -WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER - -Here is the code for each window overflow/underflow exception vector and -(interspersed) efficient code for handling the alloca exception cause. -Window exceptions are handled entirely in the vector area and are very -tight for performance. The alloca exception is also handled entirely in -the window vector area so comes at essentially no cost in code size. -Users should never need to modify them and Cadence Design Systems recommends -they do not. - -Window handlers go at predetermined vector locations according to the -Xtensa hardware configuration, which is ensured by their placement in a -special section known to the Xtensa linker support package (LSP). Since -their offsets in that section are always the same, the LSPs do not define -a section per vector. - -These things are coded for XEA2 only (XEA1 is not supported). - -Note on Underflow Handlers: -The underflow handler for returning from call[i+1] to call[i] -must preserve all the registers from call[i+1]'s window. -In particular, a0 and a1 must be preserved because the RETW instruction -will be reexecuted (and may even underflow if an intervening exception -has flushed call[i]'s registers). -Registers a2 and up may contain return values. - -*******************************************************************************/ - -#if XCHAL_HAVE_WINDOWED - - .section .WindowVectors.text, "ax" - -/* --------------------------------------------------------------------------------- -Window Overflow Exception for Call4. - -Invoked if a call[i] referenced a register (a4-a15) -that contains data from ancestor call[j]; -call[j] had done a call4 to call[j+1]. -On entry here: - window rotated to call[j] start point; - a0-a3 are registers to be saved; - a4-a15 must be preserved; - a5 is call[j+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x0 - .global _WindowOverflow4 -_WindowOverflow4: - - s32e a0, a5, -16 /* save a0 to call[j+1]'s stack frame */ - s32e a1, a5, -12 /* save a1 to call[j+1]'s stack frame */ - s32e a2, a5, -8 /* save a2 to call[j+1]'s stack frame */ - s32e a3, a5, -4 /* save a3 to call[j+1]'s stack frame */ - rfwo /* rotates back to call[i] position */ - -/* --------------------------------------------------------------------------------- -Window Underflow Exception for Call4 - -Invoked by RETW returning from call[i+1] to call[i] -where call[i]'s registers must be reloaded (not live in ARs); -where call[i] had done a call4 to call[i+1]. -On entry here: - window rotated to call[i] start point; - a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; - a4-a15 must be preserved (they are call[i+1].reg[0..11]); - a5 is call[i+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x40 - .global _WindowUnderflow4 -_WindowUnderflow4: - - l32e a0, a5, -16 /* restore a0 from call[i+1]'s stack frame */ - l32e a1, a5, -12 /* restore a1 from call[i+1]'s stack frame */ - l32e a2, a5, -8 /* restore a2 from call[i+1]'s stack frame */ - l32e a3, a5, -4 /* restore a3 from call[i+1]'s stack frame */ - rfwu - -/* --------------------------------------------------------------------------------- -Handle alloca exception generated by interruptee executing 'movsp'. -This uses space between the window vectors, so is essentially "free". -All interruptee's regs are intact except a0 which is saved in EXCSAVE_1, -and PS.EXCM has been set by the exception hardware (can't be interrupted). -The fact the alloca exception was taken means the registers associated with -the base-save area have been spilled and will be restored by the underflow -handler, so those 4 registers are available for scratch. -The code is optimized to avoid unaligned branches and minimize cache misses. --------------------------------------------------------------------------------- -*/ - - .align 4 - .global _xt_alloca_exc -_xt_alloca_exc: - - rsr a0, WINDOWBASE /* grab WINDOWBASE before rotw changes it */ - rotw -1 /* WINDOWBASE goes to a4, new a0-a3 are scratch */ - rsr a2, PS - extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS - xor a3, a3, a4 /* bits changed from old to current windowbase */ - rsr a4, EXCSAVE_1 /* restore original a0 (now in a4) */ - slli a3, a3, XCHAL_PS_OWB_SHIFT - xor a2, a2, a3 /* flip changed bits in old window base */ - wsr a2, PS /* update PS.OWB to new window base */ - rsync - - _bbci.l a4, 31, _WindowUnderflow4 - rotw -1 /* original a0 goes to a8 */ - _bbci.l a8, 30, _WindowUnderflow8 - rotw -1 - j _WindowUnderflow12 - -/* --------------------------------------------------------------------------------- -Window Overflow Exception for Call8 - -Invoked if a call[i] referenced a register (a4-a15) -that contains data from ancestor call[j]; -call[j] had done a call8 to call[j+1]. -On entry here: - window rotated to call[j] start point; - a0-a7 are registers to be saved; - a8-a15 must be preserved; - a9 is call[j+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x80 - .global _WindowOverflow8 -_WindowOverflow8: - - s32e a0, a9, -16 /* save a0 to call[j+1]'s stack frame */ - l32e a0, a1, -12 /* a0 <- call[j-1]'s sp - (used to find end of call[j]'s frame) */ - s32e a1, a9, -12 /* save a1 to call[j+1]'s stack frame */ - s32e a2, a9, -8 /* save a2 to call[j+1]'s stack frame */ - s32e a3, a9, -4 /* save a3 to call[j+1]'s stack frame */ - s32e a4, a0, -32 /* save a4 to call[j]'s stack frame */ - s32e a5, a0, -28 /* save a5 to call[j]'s stack frame */ - s32e a6, a0, -24 /* save a6 to call[j]'s stack frame */ - s32e a7, a0, -20 /* save a7 to call[j]'s stack frame */ - rfwo /* rotates back to call[i] position */ - -/* --------------------------------------------------------------------------------- -Window Underflow Exception for Call8 - -Invoked by RETW returning from call[i+1] to call[i] -where call[i]'s registers must be reloaded (not live in ARs); -where call[i] had done a call8 to call[i+1]. -On entry here: - window rotated to call[i] start point; - a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; - a8-a15 must be preserved (they are call[i+1].reg[0..7]); - a9 is call[i+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0xC0 - .global _WindowUnderflow8 -_WindowUnderflow8: - - l32e a0, a9, -16 /* restore a0 from call[i+1]'s stack frame */ - l32e a1, a9, -12 /* restore a1 from call[i+1]'s stack frame */ - l32e a2, a9, -8 /* restore a2 from call[i+1]'s stack frame */ - l32e a7, a1, -12 /* a7 <- call[i-1]'s sp - (used to find end of call[i]'s frame) */ - l32e a3, a9, -4 /* restore a3 from call[i+1]'s stack frame */ - l32e a4, a7, -32 /* restore a4 from call[i]'s stack frame */ - l32e a5, a7, -28 /* restore a5 from call[i]'s stack frame */ - l32e a6, a7, -24 /* restore a6 from call[i]'s stack frame */ - l32e a7, a7, -20 /* restore a7 from call[i]'s stack frame */ - rfwu - -/* --------------------------------------------------------------------------------- -Window Overflow Exception for Call12 - -Invoked if a call[i] referenced a register (a4-a15) -that contains data from ancestor call[j]; -call[j] had done a call12 to call[j+1]. -On entry here: - window rotated to call[j] start point; - a0-a11 are registers to be saved; - a12-a15 must be preserved; - a13 is call[j+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x100 - .global _WindowOverflow12 -_WindowOverflow12: - - s32e a0, a13, -16 /* save a0 to call[j+1]'s stack frame */ - l32e a0, a1, -12 /* a0 <- call[j-1]'s sp - (used to find end of call[j]'s frame) */ - s32e a1, a13, -12 /* save a1 to call[j+1]'s stack frame */ - s32e a2, a13, -8 /* save a2 to call[j+1]'s stack frame */ - s32e a3, a13, -4 /* save a3 to call[j+1]'s stack frame */ - s32e a4, a0, -48 /* save a4 to end of call[j]'s stack frame */ - s32e a5, a0, -44 /* save a5 to end of call[j]'s stack frame */ - s32e a6, a0, -40 /* save a6 to end of call[j]'s stack frame */ - s32e a7, a0, -36 /* save a7 to end of call[j]'s stack frame */ - s32e a8, a0, -32 /* save a8 to end of call[j]'s stack frame */ - s32e a9, a0, -28 /* save a9 to end of call[j]'s stack frame */ - s32e a10, a0, -24 /* save a10 to end of call[j]'s stack frame */ - s32e a11, a0, -20 /* save a11 to end of call[j]'s stack frame */ - rfwo /* rotates back to call[i] position */ - -/* --------------------------------------------------------------------------------- -Window Underflow Exception for Call12 - -Invoked by RETW returning from call[i+1] to call[i] -where call[i]'s registers must be reloaded (not live in ARs); -where call[i] had done a call12 to call[i+1]. -On entry here: - window rotated to call[i] start point; - a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; - a12-a15 must be preserved (they are call[i+1].reg[0..3]); - a13 is call[i+1]'s stack pointer. --------------------------------------------------------------------------------- -*/ - - .org 0x140 - .global _WindowUnderflow12 -_WindowUnderflow12: - - l32e a0, a13, -16 /* restore a0 from call[i+1]'s stack frame */ - l32e a1, a13, -12 /* restore a1 from call[i+1]'s stack frame */ - l32e a2, a13, -8 /* restore a2 from call[i+1]'s stack frame */ - l32e a11, a1, -12 /* a11 <- call[i-1]'s sp - (used to find end of call[i]'s frame) */ - l32e a3, a13, -4 /* restore a3 from call[i+1]'s stack frame */ - l32e a4, a11, -48 /* restore a4 from end of call[i]'s stack frame */ - l32e a5, a11, -44 /* restore a5 from end of call[i]'s stack frame */ - l32e a6, a11, -40 /* restore a6 from end of call[i]'s stack frame */ - l32e a7, a11, -36 /* restore a7 from end of call[i]'s stack frame */ - l32e a8, a11, -32 /* restore a8 from end of call[i]'s stack frame */ - l32e a9, a11, -28 /* restore a9 from end of call[i]'s stack frame */ - l32e a10, a11, -24 /* restore a10 from end of call[i]'s stack frame */ - l32e a11, a11, -20 /* restore a11 from end of call[i]'s stack frame */ - rfwu - -#endif /* XCHAL_HAVE_WINDOWED */ - - .section .UserEnter.text, "ax" - .global call_user_start - .type call_user_start,@function - .align 4 - .literal_position - - -call_user_start: - - movi a2, 0x40040000 /* note: absolute symbol, not a ptr */ - wsr a2, vecbase - call0 user_start /* user exception handler */ diff --git a/components/idf_test/README.md b/components/idf_test/README.md new file mode 100644 index 0000000000..f23153bca6 --- /dev/null +++ b/components/idf_test/README.md @@ -0,0 +1,61 @@ + +# Note: The test cases in this folder are for Espressif internal use. + +# Goto internal project wiki Testing page for detail about this folder. + +## File Structure + +``` +test --- CIConfigs --- sanity_test1.yml (Runner config files) + | |-- stress_test1.yml + |-- TestCaseAll.yml (TestCaseFiles) + |-- TestEnvAll.yml (TestCaseFiles) + |-- InitialConditionAll.yml (TestCaseFiles) + |-- TestCaseScript --- ... (Test case scripts) +``` + +1. CIConfigs folder + * config for CI config files are put in this folder + * CI config files configs the cases and some other options for the CI job with same name +1. Test case files + * TestCaseAll.yml (test cases) + * InitialConditionAll.yml (initial conditions) + * TestEnvAll.yml (test environments) + * [how to modify test cases](https://gitlab.espressif.cn:6688/yinling/auto_test_script/blob/master/public/Design/TestCaseFiles.DesignNote.md) +1. Test case scripts + * some cases are implemented by specified script. those scripts are put in this folder. + + +## Modify test cases + +1. check if the "SDK" of the test case only contain the current SDK + * if Yes, then just modify the test case behavior + * if No: + 1. then remove current SDK name from "SDK" of the test case + 2. Add a new test case, and set "SDK" only support current SDK name +2. use [auto_test_script](https://gitlab.espressif.cn:6688/yinling/auto_test_script) to load the modified case and verify the modification +3. create a merge request and assign to HYL (or add comment @yinling for merging test). +After review it will be merged to SDK and will be The cases will be synced to database in auto_test_script. + + +## Run test case locally + +1. clone auto_test_script (ssh://git@gitlab.espressif.cn:27227/yinling/auto_test_script.git) from gitlab +2. create test environment: + 1. search test case (search test case ID in components/test/TestCaseAll.yml, get the "test environment" value + 2. goto [test environment list](https://gitlab.espressif.cn:6688/yinling/auto_test_script/blob/master/public/Documents/TestEnvList.md), find the link and goto the environment detail page + 3. create test environment according to figure and description + 4. [config test environment](https://gitlab.espressif.cn:6688/yinling/auto_test_script/blob/master/public/Design/TestEnvConfig.DesignNote.md). All parameters in table "Parameters require config before use" MUST be configured. +3. run test cases with [CIRunner.py](https://gitlab.espressif.cn:6688/yinling/auto_test_script/blob/master/public/Design/RunnerConfigs.DesignNote.md) + + + +## exclude known issues for CI +the test cases listed in file "KnownIssues" will be excluded by CI when calculating results + +Editing KnownIssues file is very simple, one single line for the ID for each case. +``` +TCPIP_TCP_0101 +TCPIP_TCP_0201 +... +``` \ No newline at end of file diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_SYS_01.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_SYS_01.yml new file mode 100644 index 0000000000..51a6899029 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_SYS_01.yml @@ -0,0 +1,5 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC1] +Filter: +- Add: + ID: [SYS_MISC_0101, SYS_MISC_0201] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_01.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_01.yml new file mode 100644 index 0000000000..e86fac28ae --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_01.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [^TCPIP_DHCP_0302, TCPIP_DHCP_0302, TCPIP_DHCP_0301, TCPIP_TCP_0403, TCPIP_TCP_0402, + TCPIP_TCP_0401, TCPIP_TCP_0407, TCPIP_TCP_0406, ^TCPIP_TCP_0411, TCPIP_TCP_0404, + TCPIP_TCP_0408, TCPIP_TCP_0110, ^TCPIP_TCP_0111, TCPIP_TCP_0115, TCPIP_IP_0101, + TCPIP_IP_0102, ^TCPIP_IGMP_0102, ^TCPIP_IGMP_0101, ^TCPIP_IGMP_0104, TCPIP_IGMP_0104, + TCPIP_IGMP_0103, TCPIP_IGMP_0102, TCPIP_IGMP_0101, TCPIP_UDP_0108, TCPIP_UDP_0106, + TCPIP_UDP_0107, TCPIP_UDP_0105, TCPIP_UDP_0101, TCPIP_IGMP_0204, TCPIP_IGMP_0201] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_02.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_02.yml new file mode 100644 index 0000000000..a746cdd913 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_02.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [TCPIP_IGMP_0202, TCPIP_IGMP_0203, ^TCPIP_TCP_0403, ^TCPIP_TCP_0408, TCPIP_UDP_0201, + ^TCPIP_DHCP_0301, ^TCPIP_TCP_0101, ^TCPIP_TCP_0103, ^TCPIP_TCP_0105, ^TCPIP_TCP_0104, + ^TCPIP_TCP_0107, ^TCPIP_TCP_0106, ^TCPIP_DHCP_0210, ^TCPIP_DHCP_0211, ^TCPIP_DHCP_0212, + ^TCPIP_TCP_0404, TCPIP_TCP_0212, TCPIP_TCP_0210, ^TCPIP_TCP_0406, ^TCPIP_TCP_0407, + ^TCPIP_TCP_0401, ^TCPIP_TCP_0210, ^TCPIP_TCP_0212, TCPIP_DHCP_0211, TCPIP_DHCP_0210, + TCPIP_DHCP_0212, TCPIP_DHCP_0101, TCPIP_DHCP_0103, TCPIP_DHCP_0206, TCPIP_DHCP_0207] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_03.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_03.yml new file mode 100644 index 0000000000..f5f0abe5db --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_03.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [^TCPIP_IP_0102, ^TCPIP_UDP_0105, ^TCPIP_UDP_0107, ^TCPIP_UDP_0106, ^TCPIP_UDP_0101, + TCPIP_TCP_0202, ^TCPIP_UDP_0108, ^TCPIP_IGMP_0201, ^TCPIP_IGMP_0203, ^TCPIP_IGMP_0202, + ^TCPIP_IGMP_0103, TCPIP_UDP_0114, TCPIP_UDP_0113, TCPIP_UDP_0112, TCPIP_UDP_0202, + TCPIP_DHCP_0205, TCPIP_DHCP_0202, TCPIP_DHCP_0203, ^TCPIP_TCP_0102, TCPIP_TCP_0106, + TCPIP_TCP_0107, TCPIP_TCP_0104, TCPIP_TCP_0105, TCPIP_TCP_0102, TCPIP_TCP_0103, + TCPIP_TCP_0101, ^TCPIP_TCP_0116, ^TCPIP_TCP_0114, ^TCPIP_TCP_0115, ^TCPIP_TCP_0112] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_04.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_04.yml new file mode 100644 index 0000000000..b59e8c60cd --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_04.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [^TCPIP_TCP_0113, ^TCPIP_TCP_0110, TCPIP_DHCP_0209, ^TCPIP_DHCP_0209, ^TCPIP_DHCP_0207, + ^TCPIP_DHCP_0206, ^TCPIP_DHCP_0205, ^TCPIP_DHCP_0204, ^TCPIP_DHCP_0203, ^TCPIP_DHCP_0202, + ^TCPIP_DHCP_0201, TCPIP_TCP_0204, TCPIP_TCP_0207, TCPIP_TCP_0206, TCPIP_TCP_0201, + ^TCPIP_DHCP_0101, TCPIP_TCP_0203, ^TCPIP_DHCP_0103, ^TCPIP_DHCP_0208, TCPIP_TCP_0208, + ^TCPIP_TCP_0202, ^TCPIP_TCP_0203, TCPIP_DHCP_0204, ^TCPIP_TCP_0201, ^TCPIP_TCP_0206, + ^TCPIP_TCP_0207, ^TCPIP_TCP_0204, TCPIP_DHCP_0201, ^TCPIP_TCP_0208, TCPIP_DHCP_0208] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_05.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_05.yml new file mode 100644 index 0000000000..627d67c408 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_05.yml @@ -0,0 +1,8 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [^TCPIP_IGMP_0204, ^TCPIP_TCP_0412, TCPIP_TCP_0411, TCPIP_TCP_0412, ^TCPIP_UDP_0112, + ^TCPIP_UDP_0113, ^TCPIP_UDP_0114, ^TCPIP_UDP_0202, ^TCPIP_UDP_0201, ^TCPIP_IP_0101, + ^TCPIP_TCP_0402, TCPIP_TCP_0114, TCPIP_TCP_0116, TCPIP_TCP_0111, TCPIP_TCP_0113, + TCPIP_TCP_0112] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_06.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_06.yml new file mode 100644 index 0000000000..7cf6279995 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_06.yml @@ -0,0 +1,5 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC1] +Filter: +- Add: + ID: [TCPIP_TCP_0405, ^TCPIP_TCP_0405] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_07.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_07.yml new file mode 100644 index 0000000000..839ac972f4 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_07.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [TCPIP_UDP_0303, TCPIP_UDP_0303, TCPIP_UDP_0303, TCPIP_UDP_0303, TCPIP_UDP_0303, + TCPIP_ICMP_0101, TCPIP_ICMP_0101, TCPIP_ICMP_0101, TCPIP_ICMP_0101, TCPIP_ICMP_0101, + TCPIP_DNS_0102, TCPIP_DNS_0102, TCPIP_DNS_0102, TCPIP_DNS_0102, TCPIP_DNS_0102, + TCPIP_DNS_0101, TCPIP_DNS_0101, TCPIP_DNS_0101, TCPIP_DNS_0101, TCPIP_DNS_0101, + ^TCPIP_ICMP_0101, ^TCPIP_ICMP_0101, ^TCPIP_ICMP_0101, ^TCPIP_ICMP_0101, ^TCPIP_ICMP_0101, + TCPIP_UDP_0109, TCPIP_UDP_0109, TCPIP_UDP_0109, TCPIP_UDP_0109, TCPIP_UDP_0109] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_08.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_08.yml new file mode 100644 index 0000000000..b318b09377 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_08.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC1] +Filter: +- Add: + ID: [TCPIP_UDP_0104, TCPIP_UDP_0104, TCPIP_UDP_0104, TCPIP_UDP_0104, TCPIP_UDP_0104, + TCPIP_UDP_0102, TCPIP_UDP_0102, TCPIP_UDP_0102, TCPIP_UDP_0102, TCPIP_UDP_0102, + TCPIP_UDP_0103, TCPIP_UDP_0103, TCPIP_UDP_0103, TCPIP_UDP_0103, TCPIP_UDP_0103, + ^TCPIP_UDP_0307, ^TCPIP_UDP_0307, ^TCPIP_UDP_0307, ^TCPIP_UDP_0307, ^TCPIP_UDP_0307, + ^TCPIP_UDP_0306, ^TCPIP_UDP_0306, ^TCPIP_UDP_0306, ^TCPIP_UDP_0306, ^TCPIP_UDP_0306, + ^TCPIP_UDP_0305, ^TCPIP_UDP_0305, ^TCPIP_UDP_0305, ^TCPIP_UDP_0305, ^TCPIP_UDP_0305] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_09.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_09.yml new file mode 100644 index 0000000000..50b50a3eb6 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_09.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC1] +Filter: +- Add: + ID: [^TCPIP_UDP_0304, ^TCPIP_UDP_0304, ^TCPIP_UDP_0304, ^TCPIP_UDP_0304, ^TCPIP_UDP_0304, + ^TCPIP_UDP_0302, ^TCPIP_UDP_0302, ^TCPIP_UDP_0302, ^TCPIP_UDP_0302, ^TCPIP_UDP_0302, + ^TCPIP_UDP_0301, ^TCPIP_UDP_0301, ^TCPIP_UDP_0301, ^TCPIP_UDP_0301, ^TCPIP_UDP_0301, + ^TCPIP_UDP_0104, ^TCPIP_UDP_0104, ^TCPIP_UDP_0104, ^TCPIP_UDP_0104, ^TCPIP_UDP_0104, + ^TCPIP_UDP_0103, ^TCPIP_UDP_0103, ^TCPIP_UDP_0103, ^TCPIP_UDP_0103, ^TCPIP_UDP_0103, + ^TCPIP_UDP_0102, ^TCPIP_UDP_0102, ^TCPIP_UDP_0102, ^TCPIP_UDP_0102, ^TCPIP_UDP_0102] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_10.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_10.yml new file mode 100644 index 0000000000..44b7bd1893 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_10.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [TCPIP_UDP_0111, TCPIP_UDP_0111, TCPIP_UDP_0111, TCPIP_UDP_0111, TCPIP_UDP_0111, + TCPIP_UDP_0110, TCPIP_UDP_0110, TCPIP_UDP_0110, TCPIP_UDP_0110, TCPIP_UDP_0110, + ^TCPIP_DNS_0101, ^TCPIP_DNS_0101, ^TCPIP_DNS_0101, ^TCPIP_DNS_0101, ^TCPIP_DNS_0101, + ^TCPIP_DNS_0103, ^TCPIP_DNS_0103, ^TCPIP_DNS_0103, ^TCPIP_DNS_0103, ^TCPIP_DNS_0103, + ^TCPIP_DNS_0102, ^TCPIP_DNS_0102, ^TCPIP_DNS_0102, ^TCPIP_DNS_0102, ^TCPIP_DNS_0102, + TCPIP_UDP_0304, TCPIP_UDP_0304, TCPIP_UDP_0304, TCPIP_UDP_0304, TCPIP_UDP_0304] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_11.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_11.yml new file mode 100644 index 0000000000..be615d0878 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_11.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC1] +Filter: +- Add: + ID: [TCPIP_UDP_0305, TCPIP_UDP_0305, TCPIP_UDP_0305, TCPIP_UDP_0305, TCPIP_UDP_0305, + TCPIP_UDP_0306, TCPIP_UDP_0306, TCPIP_UDP_0306, TCPIP_UDP_0306, TCPIP_UDP_0306, + TCPIP_UDP_0307, TCPIP_UDP_0307, TCPIP_UDP_0307, TCPIP_UDP_0307, TCPIP_UDP_0307, + TCPIP_UDP_0301, TCPIP_UDP_0301, TCPIP_UDP_0301, TCPIP_UDP_0301, TCPIP_UDP_0301, + TCPIP_UDP_0302, TCPIP_UDP_0302, TCPIP_UDP_0302, TCPIP_UDP_0302, TCPIP_UDP_0302, + TCPIP_DNS_0103, TCPIP_DNS_0103, TCPIP_DNS_0103, TCPIP_DNS_0103, TCPIP_DNS_0103] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_12.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_12.yml new file mode 100644 index 0000000000..73b0187eed --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_TCPIP_12.yml @@ -0,0 +1,6 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC1] +Filter: +- Add: + ID: [^TCPIP_UDP_0303, ^TCPIP_UDP_0303, ^TCPIP_UDP_0303, ^TCPIP_UDP_0303, ^TCPIP_UDP_0303, + ^TCPIP_UDP_0110, ^TCPIP_UDP_0110, ^TCPIP_UDP_0110, ^TCPIP_UDP_0110, ^TCPIP_UDP_0110] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_01.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_01.yml new file mode 100644 index 0000000000..9f8424f6d2 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_01.yml @@ -0,0 +1,10 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [^WIFI_CONN_0601, ^WIFI_ADDR_0101, WIFI_SCAN_0103, WIFI_SCAN_0102, WIFI_SCAN_0101, + WIFI_SCAN_0105, WIFI_SCAN_0104, ^WIFI_CONN_0103, WIFI_CONN_0201, WIFI_CONN_0904, + ^WIFI_SCAN_0102, ^WIFI_SCAN_0103, ^WIFI_SCAN_0104, WIFI_CONN_0401, WIFI_ADDR_0101, + WIFI_ADDR_0102, WIFI_CONN_0301, WIFI_SCAN_0301, WIFI_SCAN_0303, ^WIFI_CONN_0801, + WIFI_SCAN_0304, ^WIFI_CONN_0301, WIFI_CONN_0501, WIFI_CONN_0502, ^WIFI_CONN_0401, + WIFI_MODE_0101, WIFI_MODE_0103, WIFI_MODE_0102, ^WIFI_CONN_0904, ^WIFI_CONN_0901] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_02.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_02.yml new file mode 100644 index 0000000000..74e6ca612d --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_02.yml @@ -0,0 +1,7 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [WIFI_SCAN_0302, WIFI_CONN_0601, ^WIFI_CONN_0201, ^WIFI_ADDR_0102, WIFI_CONN_0901, + WIFI_CONN_0801, ^WIFI_CONN_0104, WIFI_CONN_0104, WIFI_CONN_0101, WIFI_CONN_0102, + WIFI_CONN_0103, ^WIFI_SCAN_0101, ^WIFI_CONN_0101, ^WIFI_CONN_0502, ^WIFI_CONN_0501] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_03.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_03.yml new file mode 100644 index 0000000000..0f0b4bbaad --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_03.yml @@ -0,0 +1,6 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC3, SSC2, SSC1] +Filter: +- Add: + ID: [WIFI_PHY_0502, WIFI_PHY_0503, WIFI_PHY_0501, WIFI_PHY_0506, WIFI_PHY_0505, + WIFI_PHY_0504] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_04.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_04.yml new file mode 100644 index 0000000000..50f8707c72 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_04.yml @@ -0,0 +1,5 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC1] +Filter: +- Add: + ID: [^WIFI_CONN_0902, WIFI_CONN_0902] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_05.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_05.yml new file mode 100644 index 0000000000..3694a698b7 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_05.yml @@ -0,0 +1,5 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC1] +Filter: +- Add: + ID: [^WIFI_CONN_0903, WIFI_CONN_0903] diff --git a/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_06.yml b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_06.yml new file mode 100644 index 0000000000..dd42815a91 --- /dev/null +++ b/components/idf_test/integration_test/CIConfigs/IT_Function_WIFI_06.yml @@ -0,0 +1,6 @@ +Config: {execute count: 1, execute order: in order} +DUT: [SSC2, SSC1] +Filter: +- Add: + ID: [WIFI_SCAN_0201, WIFI_PHY_0403, WIFI_PHY_0402, WIFI_PHY_0401, WIFI_PHY_0407, + WIFI_PHY_0406, WIFI_PHY_0405, WIFI_PHY_0404, WIFI_PHY_0408] diff --git a/components/idf_test/integration_test/InitialConditionAll.yml b/components/idf_test/integration_test/InitialConditionAll.yml new file mode 100644 index 0000000000..3821894552 --- /dev/null +++ b/components/idf_test/integration_test/InitialConditionAll.yml @@ -0,0 +1,2959 @@ +initial condition: +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + initial condition detail: AP mode, DHCP on, will autogen a TC with initial condition + APSTA1 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 31.0 + tag: APM1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 ap -L + - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + initial condition detail: AP mode, PC join AP, DHCP on, will autogen a TC with initial + condition APSTA2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 38.0 + tag: APM2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + initial condition detail: AP mode, will NOT autogen a TC with initial condition + APSTA1 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 31.0 + tag: APO1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 ap -L + - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + initial condition detail: AP mode, will NOT autogen a TC with initial condition + APSTA2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 38.0 + tag: APO2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 1 + - ['R SSC1 C BIN_ID,0'] + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + force restore cmd set: + - '' + - - SSC SSC1 upgrade -R -r 1 -s + - [R SSC1 NC ERROR C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SOC SOC1 ULISTEN + - [R SOC_COM L OK] + - - SOC SOC1 SETOPT REPLY BIN + - [R SOC_COM C OK] + - - SSC SSC1 upgrade -I -b 0 -f 0 + - ['P SSC1 C +UPGRADE:OK'] + - - SSC SSC1 upgrade -U -i -p -u + - ['P SSC1 C +UPGRADE:SUCCEED'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + initial condition detail: AP only mode, running BIN0 (located on flash id 0) + restore cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + restore post cmd set: + - '' + - - SSC SSC1 upgrade -D + - ['R SSC1 C +UPGRADE:OK'] + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 31.0 + tag: APOBIN0 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + initial condition detail: testing ap on sta + ap mode (autogen by APM1) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 59.0 + tag: APSTA1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 ap -L + - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + initial condition detail: testing ap on sta + ap mode, PC join AP (autogen by APM2) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 66.0 + tag: APSTA2 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - DELAY 5 + - [''] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + initial condition detail: StationSoftAP mode + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 24.0 + tag: ATAP1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:3 L OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - DELAY 5 + - [''] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + initial condition detail: StationSoftAP mode, PC join Target AP, multi link, use + dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 R *] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 31.0 + tag: ATAP3 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:3 L OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - DELAY 10 + - [''] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: StationSoftAP mode, PC join Target AP, single link, use + dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 45.0 + tag: ATAP4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: StationSoftAP mode, both PC join Target AP, single link, + use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATAP5 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: StationSoftAP mode, both PC join Target AP, multi link, + use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATAP6 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:2'] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + initial condition detail: SoftAP mode, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 59.0 + tag: ATAPO1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:2 L OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + initial condition detail: SoftAP mode, PC join Target AP, multi link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 R *] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 66.0 + tag: ATAPO3 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:2 L OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: SoftAP mode, PC join Target AP, single link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 73.0 + tag: ATAPO4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: SoftAP mode, both PC join Target AP, single link, use + dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATAPO5 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: SoftAP mode, both PC join Target AP, multi link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATAPO6 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + initial condition detail: StationSoftAP mode + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 87.0 + tag: ATAPSTA1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + initial condition detail: StationSoftAP mode, DHCP client on + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 87.0 + tag: ATAPSTA2 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + initial condition detail: StationSoftAP mode, connected to AP, multi link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 94.0 + tag: ATAPSTA3 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: StationSoftAP mode, connected to AP, single link, use + dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 101.0 + tag: ATAPSTA4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + initial condition detail: StationSoftAP mode, connected to AP, multi link, use static + ip + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 129.0 + tag: ATAPSTA5 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + initial condition detail: StationSoftAP mode, connected to AP, single link, use + static ip + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 136.0 + tag: ATAPSTA6 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT+RESTORE + - [R AT1 L OK, R AT1 C ready] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT+RESTORE + - [R AT1 L OK, R AT1 C ready] + initial condition detail: 'first time usage. Use restore function. ' + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+RESTORE + - [R AT1 L OK, R AT1 C ready] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 143.0 + tag: ATFTU + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: none + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATNone + test script: InitCondBase +- check cmd set: + - '' + - - DELAY 0.1 + - [dummy] + force restore cmd set: + - '' + - - DELAY 0.1 + - [dummy] + initial condition detail: none 2 + restore cmd set: + - '' + - - DELAY 0.1 + - [dummy] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 108.0 + tag: ATNone2 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + initial condition detail: same as STA1, but will not autogen STA+AP STA test case + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 10.0 + tag: ATOSTA1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: same as STA4, but will not autogen STA+AP STA test case + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: ATOSTA4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:3 C OK'] + - - ATS AT2 AT+CWMODE_CUR? + - ['R AT2 C +CWMODE_CUR:1 C OK'] + - - ATS AT1 AT+CWJAP_CUR? + - [R AT1 NC OK L ERROR] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=1 + - [R AT2 L OK] + - - ATS AT1 AT+CWQAP + - [R AT1 L OK] + initial condition detail: same as OT2_1, but will not autogen STA+AP STA test case + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=1 + - [R AT2 L OK] + - - ATS AT1 AT+CWQAP + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 52.0 + tag: ATOT2_1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + initial condition detail: station mode, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 10.0 + tag: ATSTA1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + initial condition detail: station mode, DHCP client on, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 10.0 + tag: ATSTA2 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + initial condition detail: station mode, connected to AP, multi link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 38.0 + tag: ATSTA3 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: station mode, connected to AP, single link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: ATSTA4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + initial condition detail: station mode, connected to AP, multi link, use static + ip + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 115.0 + tag: ATSTA5 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + initial condition detail: station mode, connected to AP, single link, use static + ip + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 122.0 + tag: ATSTA6 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:3 C OK'] + - - ATS AT2 AT+CWMODE_CUR? + - ['R AT2 C +CWMODE_CUR:1 C OK'] + - - ATS AT1 AT+CWJAP_CUR? + - [R AT1 NC OK L ERROR] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=1 + - [R AT2 L OK] + - - ATS AT1 AT+CWQAP + - [R AT1 L OK] + initial condition detail: Target 1 in StationSoftAP mode, Target 2 in station mode, + use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=1 + - [R AT2 L OK] + - - ATS AT1 AT+CWQAP + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 52.0 + tag: ATT2_1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:2 C OK'] + - - ATS AT2 AT+CWMODE_CUR? + - ['R AT2 C +CWMODE_CUR:3 C OK'] + - - ATS AT1 AT+CWJAP_CUR? + - [R AT1 NC OK L ERROR] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=3 + - [R AT2 L OK] + initial condition detail: Target 1 in SoftAP mode, Target 2 in StationSoftAP mode, + use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=3 + - [R AT2 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 80.0 + tag: ATT2_2 + test script: InitCondBase +- check cmd set: + - '' + - - ASSERT + - [dummy] + force restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['P SSC[1-] C !!!ready!!!'] + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] op -S -o 1 + - ['P SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] sta -D + - ['P SSC[1-] C +QAP:OK'] + initial condition detail: all mesh node disabled + restore cmd set: + - '' + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] op -S -o 1 + - ['P SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] sta -D + - ['P SSC[1-] C +QAP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 31.0 + tag: DISABLED + test script: InitCondBase +- check cmd set: + - '' + - - ASSERT + - [dummy] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + force restore cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] mesh -I -g -a 4 -k -i + -p -h 5 + - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] + - - SSC SSC[1-] mesh -A -s -k + - ['P SSC[1-] C +MESHINIT:AP,OK'] + - - SSC SSC1 mesh -E -o 1 -t 2 + - ['P SSC1 C +MESH:ENABLED'] + - - SOC SOC1 MACCEPT GSOC1 + - [R SOC_COM L OK] + - - SSC SSC[2-] mesh -E -o 1 -t 2 + - ['P SSC[2-] C +MESH:ENABLED'] + - - DELAY 60 + - [''] + - - SSC SSC[1-] mesh -C + - ['P SSC[1-] C +MESH:CONNECTED'] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + - - SSC SSC[1-] mesh -O -t 1 -o 1 + - ['P SSC[1-] C +MESH:OK'] + initial condition detail: all mesh node enabled as ONLINE, mesh network established + restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['P SSC[1-] C !!!ready!!!'] + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] mesh -I -g -a 4 -k -i + -p -h 5 + - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] + - - SSC SSC[1-] mesh -A -s -k + - ['P SSC[1-] C +MESHINIT:AP,OK'] + - - SSC SSC1 mesh -E -o 1 -t 2 + - ['P SSC1 C +MESH:ENABLED'] + - - SOC SOC1 MACCEPT GSOC1 + - [R SOC_COM L OK] + - - SSC SSC[2-] mesh -E -o 1 -t 2 + - ['P SSC[2-] C +MESH:ENABLED'] + - - DELAY 60 + - [''] + - - SSC SSC[1-] mesh -C + - ['P SSC[1-] C +MESH:CONNECTED'] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + - - SSC SSC[1-] mesh -O -t 1 -o 1 + - ['P SSC[1-] C +MESH:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: ENABLED_1 + test script: InitCondBase +- check cmd set: + - '' + - - ASSERT + - [dummy] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + force restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['P SSC[1-] C !!!ready!!!'] + - - SSC SSC[1-] mesh -I -g -a 4 -k -i + -p -h 5 + - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] + - - SSC SSC1 mesh -A -s -k + - ['P SSC1 C +MESHINIT:AP,OK'] + - - SSC SSC1 mesh -E -o 1 -t 1 + - ['P SSC1 C +MESH:ENABLED'] + - - SSC SSC[2-] mesh -E -o 1 -t 2 + - [''] + - - DELAY 60 + - ['P SSC[2-] C +MESH:ENABLED'] + - - SSC SSC[1-] mesh -C + - ['P SSC[1-] C +MESH:CONNECTED'] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + initial condition detail: root as LOCAL, rest node as ONLINE, mesh network established + restore cmd set: + - '' + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] mesh -I -g -a 4 -k -i + -p -h 5 + - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] + - - SSC SSC1 mesh -A -s -k + - ['P SSC1 C +MESHINIT:AP,OK'] + - - SSC SSC1 mesh -E -o 1 -t 1 + - ['P SSC1 C +MESH:ENABLED'] + - - SSC SSC[2-] mesh -E -o 1 -t 2 + - [''] + - - DELAY 60 + - ['P SSC[2-] C +MESH:ENABLED'] + - - SSC SSC[1-] mesh -C + - ['P SSC[1-] C +MESH:CONNECTED'] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 24.0 + tag: ENABLED_2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + - - SSC SSC1 espnow -D + - ['R SSC1 C +ESPNOW:'] + force restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['R SSC[1-] C !!!ready!!!'] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -m -o 2 + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 espnow -D + - ['R SSC1 C +ESPNOW:'] + initial condition detail: one target in AP mode and espnow is de-initialized + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -m -o 2 + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 espnow -D + - ['R SSC1 C +ESPNOW:'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: NOW1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC[1-] op -Q + - ['R SSC[1-] C +CURMODE:2'] + - - SSC SSC[1-] mac -Q -o 3 + - ['R SSC[1-] P ]_ap_mac> P ]_mac>'] + - - SSC SSC[1-] espnow -D + - ['R SSC[1-] C +ESPNOW:'] + - - SSC SSC[1-] espnow -I + - ['R SSC[1-] C +ESPNOW:OK'] + - - SSC SSC[1-] espnow -R -t Set -r 2 + - ['R SSC[1-] C +ESPNOW:OK'] + force restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['R SSC[1-] C !!!ready!!!'] + - - SSC SSC[1-] op -S -o 3 + - ['R SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 + - ['R SSC[1-] C +MAC:AP,OK'] + - - SSC SSC[1-] mac -S -m ]_mac> -o 1 + - ['R SSC[1-] C +MAC:STA,OK'] + - - SSC SSC[1-] op -S -o 2 + - ['R SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] espnow -D + - ['R SSC[1-] C +ESPNOW:'] + - - SSC SSC[1-] espnow -I + - ['R SSC[1-] C +ESPNOW:OK'] + - - SSC SSC[1-] espnow -R -t Set -r 2 + - ['R SSC[1-] C +ESPNOW:OK'] + initial condition detail: multiple () targets in AP mode, espnow is initialized + with self role slave + restore cmd set: + - '' + - - SSC SSC[1-] op -S -o 3 + - ['R SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 + - ['R SSC[1-] C +MAC:AP,OK'] + - - SSC SSC[1-] mac -S -m ]_mac> -o 1 + - ['R SSC[1-] C +MAC:STA,OK'] + - - SSC SSC[1-] op -S -o 2 + - ['R SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] espnow -D + - ['R SSC[1-] C +ESPNOW:'] + - - SSC SSC[1-] espnow -I + - ['R SSC[1-] C +ESPNOW:OK'] + - - SSC SSC[1-] espnow -R -t Set -r 2 + - ['R SSC[1-] C +ESPNOW:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 24.0 + tag: NOW2 + test script: InitCondBase +- check cmd set: + - '' + - - DELAY 0.1 + - [dummy] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + initial condition detail: none + restore cmd set: + - '' + - - DELAY 0.1 + - [dummy] + restore post cmd set: + - '' + - - DELAY 0.1 + - [dummy] + script path: InitCondBase.py + start: 10.0 + tag: None + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 sp -D + - ['R SSC1 C +SP:OK'] + force restore cmd set: + - '' + - - SSC SSC1 sp -D + - ['R SSC1 C +SP:OK'] + initial condition detail: one target and simple is de-inited + restore cmd set: + - '' + - - SSC SSC1 sp -D + - ['R SSC1 C +SP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 31.0 + tag: PAIR1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC[1,2] op -Q + - ['R SSC[1,2] C +MODE:[2,1]'] + - - SSC SSC[1,2] mac -Q -o 3 + - ['R SSC[1,2] P P '] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + force restore cmd set: + - '' + - - SSC SSC[1,2] reboot + - ['R SSC[1,2] C !!!ready!!!'] + - - SSC SSC[1,2] op -S -o 3 + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] mac -S -m -o 2 + - ['R SSC[1,2] C +MAC:AP,OK'] + - - SSC SSC[1,2] mac -S -m -o 1 + - ['R SSC[1,2] C +MAC:STA,OK'] + - - SSC SSC[1,2] op -S -o [2,1] + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + initial condition detail: target1 in AP mode, target2 in STA mode, two targets de-init + and init simple pair + restore cmd set: + - '' + - - SSC SSC[1,2] op -S -o 3 + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] mac -S -m -o 2 + - ['R SSC[1,2] C +MAC:AP,OK'] + - - SSC SSC[1,2] mac -S -m -o 1 + - ['R SSC[1,2] C +MAC:STA,OK'] + - - SSC SSC[1,2] op -S -o [2,1] + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 38.0 + tag: PAIR2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC[1,2] op -Q + - ['R SSC[1,2] C +MODE:[3,3]'] + - - SSC SSC[1,2] mac -Q -o 3 + - ['R SSC[1,2] P P '] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + force restore cmd set: + - '' + - - SSC SSC[1,2] reboot + - ['R SSC[1,2] C !!!ready!!!'] + - - SSC SSC[1,2] op -S -o [3,3] + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] mac -S -m -o 2 + - ['R SSC[1,2] C +MAC:AP,OK'] + - - SSC SSC[1,2] mac -S -m -o 1 + - ['R SSC[1,2] C +MAC:STA,OK'] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + initial condition detail: target1 and target2 in STA+AP mode, two targets de-init + and init simple pair + restore cmd set: + - '' + - - SSC SSC[1,2] op -S -o [3,3] + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] mac -S -m -o 2 + - ['R SSC[1,2] C +MAC:AP,OK'] + - - SSC SSC[1,2] mac -S -m -o 1 + - ['R SSC[1,2] C +MAC:STA,OK'] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 45.0 + tag: PAIR3 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + initial condition detail: testing sta on sta + ap mode, quit AP (autogen by STAM1) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 45.0 + tag: STAAP1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC1 sta -Q + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: testing sta on sta + ap mode, join AP, DHCP on (autogen + by STAM2) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 52.0 + tag: STAAP2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 1 + - ['R SSC1 C BIN_ID,0'] + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + force restore cmd set: + - '' + - - SSC SSC1 upgrade -R -r 1 -s + - [R SSC1 NC ERROR C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SOC SOC1 ULISTEN + - [R SOC_COM L OK] + - - SOC SOC1 SETOPT REPLY BIN + - [R SOC_COM C OK] + - - SSC SSC1 upgrade -I -b 0 -f 0 + - ['P SSC1 C +UPGRADE:OK'] + - - SSC SSC1 upgrade -U -i -p -u + - ['P SSC1 C +UPGRADE:SUCCEED'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: APSTA mode, connected to AP, running BIN0 (located on + flash id 0) + restore cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 upgrade -D + - ['R SSC1 C +UPGRADE:OK'] + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 24.0 + tag: STAAPBIN0 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:1'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + initial condition detail: sta mode, quit AP, DHCP on, will autogen a TC with initial + condition STAAP1 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 17.0 + tag: STAM1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:1'] + - - SSC SSC1 sta -Q + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: sta mode, join AP, DHCP on, will autogen a TC with initial + condition STAAP2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 24.0 + tag: STAM2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 1 + - ['R SSC1 C BIN_ID,0'] + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + force restore cmd set: + - '' + - - SSC SSC1 upgrade -R -r 1 -s + - [R SSC1 NC ERROR C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SOC SOC1 ULISTEN + - [R SOC_COM L OK] + - - SOC SOC1 SETOPT REPLY BIN + - [R SOC_COM C OK] + - - SSC SSC1 upgrade -I -b 0 -f 0 + - ['P SSC1 C +UPGRADE:OK'] + - - SSC SSC1 upgrade -U -i -p -u + - ['P SSC1 C +UPGRADE:SUCCEED'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: STA mode, connected to AP, running BIN0 (located on flash + id 0) + restore cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 upgrade -D + - ['R SSC1 C +UPGRADE:OK'] + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: STAMBIN0 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:1'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + initial condition detail: sta mode, quit AP, will NOT autogen a TC with initial + condition STAAP1 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 17.0 + tag: STAO1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:1'] + - - SSC SSC1 sta -Q + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: sta mode, join AP, DHCP on, will NOT autogen a TC with + initial condition STAAP2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 24.0 + tag: STAO2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC2 op -Q + - ['R SSC2 C +CURMODE:1'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC2 dhcp -Q -o 1 + - ['R SSC2 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + - - SSC SSC2 mac -Q -o 1 + - [R SSC2 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC2 reboot + - [R SSC2 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + initial condition detail: same as T2_1 but will NOT autogen a TC with initial condition + T2_2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 73.0 + tag: T2O_1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC2 op -Q + - ['R SSC2 C +CURMODE:1'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC2 dhcp -Q -o 1 + - ['R SSC2 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + - - SSC SSC2 mac -Q -o 1 + - [R SSC2 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC2 reboot + - [R SSC2 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + initial condition detail: target 1 as SoftAP, target 2 as STA, will autogen a TC + with initial condition T2_2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 73.0 + tag: T2_1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC2 op -Q + - ['R SSC2 C +CURMODE:3'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [R SSC2 C +CLOSEALL] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC2 dhcp -Q -o 1 + - ['R SSC2 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + - - SSC SSC2 mac -Q -o 1 + - [R SSC2 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC2 reboot + - [R SSC2 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 3 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [R SSC2 C +CLOSEALL] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + initial condition detail: target 1 as AP+STA, target 2 as AP+STA (autogen) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 3 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [R SSC2 C +CLOSEALL] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 80.0 + tag: T2_2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC[1-3] op -Q + - ['R SSC[1-3] C +CURMODE:3'] + - - SSC SSC[1-3] phy -Q -o 3 + - ['R SSC[1-3] C STA,n,40 C AP,n,40'] + force restore cmd set: + - '' + - - SSC SSC[1-3] reboot + - ['R SSC[1-3] C !!!ready!!!'] + - - SSC SSC[1-3] op -S -o 3 + - ['R SSC[1-3] C +MODE:OK'] + - - SSC SSC[1-3] phy -S -o 3 -m n -b 40 + - ['R SSC[1-3] C +PHY:OK'] + initial condition detail: '1. target 1 and target 2 set to AP+STA mode, target 3 + set to STA mode + + 2. all interface of target 2,3 set to 11n ht40 + + 3. config softAP of target 1 and target 2' + restore cmd set: + - '' + - - SSC SSC[1-3] op -S -o 3 + - ['R SSC[1-3] C +MODE:OK'] + - - SSC SSC[1-3] phy -S -o 3 -m n -b 40 + - ['R SSC[1-3] C +PHY:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 sta -R -r 1 + - [R SSC1 C OK] + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 87.0 + tag: T3_PHY1 + test script: InitCondBase +- check cmd set: + - '' + - - UT UT1 - + - [R UT1 C Tests C Failures C Ignored] + force restore cmd set: + - '' + - - FREBOOT UT1 + - [''] + - - UT UT1 - + - [R UT1 C Tests C Failures C Ignored] + initial condition detail: At UT menu page + restore cmd set: + - '' + - - FREBOOT UT1 + - [''] + - - UT UT1 - + - [R UT1 C Tests C Failures C Ignored] + restore post cmd set: + - '' + - - DELAY 0.1 + - [''] + script path: InitCondBase.py + tag: UTINIT1 + test script: InitCondBase diff --git a/components/idf_test/integration_test/KnownIssues b/components/idf_test/integration_test/KnownIssues new file mode 100644 index 0000000000..e0991f39b0 --- /dev/null +++ b/components/idf_test/integration_test/KnownIssues @@ -0,0 +1,106 @@ + +# NOT SUPPORT + +# ICMP send Ping not supported +TCPIP_ICMP_0101 +^TCPIP_ICMP_0101 + +# IGMP cases are not supported for now +TCPIP_IGMP_0101 +TCPIP_IGMP_0102 +TCPIP_IGMP_0103 +TCPIP_IGMP_0104 +TCPIP_IGMP_0201 +TCPIP_IGMP_0202 +TCPIP_IGMP_0203 +TCPIP_IGMP_0204 +^TCPIP_IGMP_0101 +^TCPIP_IGMP_0102 +^TCPIP_IGMP_0103 +^TCPIP_IGMP_0104 +^TCPIP_IGMP_0201 +^TCPIP_IGMP_0202 +^TCPIP_IGMP_0203 +^TCPIP_IGMP_0204 + +# don't support PHY mode command +WIFI_SCAN_0201 +WIFI_SCAN_0302 +WIFI_PHY_0401 +WIFI_PHY_0402 +WIFI_PHY_0403 +WIFI_PHY_0404 +WIFI_PHY_0405 +WIFI_PHY_0407 +WIFI_PHY_0406 +WIFI_PHY_0408 +WIFI_PHY_0501 +WIFI_PHY_0502 +WIFI_PHY_0503 +WIFI_PHY_0504 +WIFI_PHY_0505 +WIFI_PHY_0506 + +# BUG + +# auth change event +WIFI_CONN_0801 +^WIFI_CONN_0801 + +# disconnect reason +WIFI_CONN_0904 +^WIFI_CONN_0904 +WIFI_CONN_0901 +^WIFI_CONN_0901 + +# Wifi connect issue +WIFI_CONN_0104 +^WIFI_CONN_0104 +^WIFI_CONN_0601 + +# Wifi scan issue +WIFI_SCAN_0303 +^WIFI_SCAN_0103 +^WIFI_SCAN_0105 + +# set mac address may lead to exception +WIFI_ADDR_0101 +^WIFI_ADDR_0101 + +# DHCP issues +^TCPIP_DHCP_0301 +TCPIP_DHCP_0301 +TCPIP_DHCP_0101 +TCPIP_DHCP_0207 +^TCPIP_DHCP_0207 +TCPIP_DHCP_0208 +^TCPIP_DHCP_0208 +TCPIP_DHCP_0205 +^TCPIP_DHCP_0205 +TCPIP_DHCP_0209 +^TCPIP_DHCP_0209 + +# TCP issue +TCPIP_TCP_0402 +^TCPIP_TCP_0406 +^TCPIP_TCP_0401 +TCPIP_TCP_0210 +^TCPIP_TCP_0210 +TCPIP_TCP_0103 +^TCPIP_TCP_0103 +TCPIP_TCP_0112 +^TCPIP_TCP_0112 + + +# UDP issue +TCPIP_UDP_0103 +^TCPIP_UDP_0103 +TCPIP_UDP_0110 +^TCPIP_UDP_0110 +TCPIP_UDP_0305 +^TCPIP_UDP_0305 +^TCPIP_UDP_0304 +TCPIP_UDP_0104 + + + diff --git a/components/idf_test/integration_test/TestCaseAll.yml b/components/idf_test/integration_test/TestCaseAll.yml new file mode 100644 index 0000000000..9e4823a297 --- /dev/null +++ b/components/idf_test/integration_test/TestCaseAll.yml @@ -0,0 +1,14639 @@ +test cases: +- CI ready: 'Yes' + ID: SYS_MISC_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + comment: '' + execution time: 0.0 + expected result: 重启成功 + initial condition: None + initial condition description (auto): none + level: Integration + module: System + steps: 系统重启 + sub module: Misc + summary: test reboot function + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: sw reboot + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: SYS_MISC_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ram -H + - ['R SSC1 RE FREEHEAP:\d+\r\n'] + comment: '' + execution time: 0.0 + expected result: ' + + 可以查询到一个数值 + + ' + initial condition: None + initial condition description (auto): none + level: Integration + module: System + steps: 查询空闲ram + sub module: Misc + summary: get heap size test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: 'get heap size ' + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -i 0.0.0.0 + - [R SSC1 C +IP] + - - SSC SSC1 sta -C -s -p + - [''] + - - DELAY 20 + - [P PC_COM C +DELAYDONE, 'P SSC1 NC +JAP:CONNECTED'] + - - SSC SSC1 dhcp -S -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -Q + - ['R SSC1 C +STAIP:0.0.0.0'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC1 ip -Q + - ['R SSC1 RE "\+STAIP:%%s"%%()'] + comment: '' + execution time: 0.0 + expected result: "1.target1 关闭DHCP OK\n2.target1 设置ip add OK\n3.target1 连接AP fail\n\ + 4.target1 打开DHCP OK\n5.查询到sta ip \n6.target1 连接AP ok\n7.查询到sta ip 为target_ip" + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: TCPIP + steps: "1.target1 关闭DHCP OK\n2.target1 设置ip add OK\n3.target1 连接AP fail\n4.target1\ + \ 打开DHCP OK\n5.查询到sta ip \n6.target1 连接AP ok\n7.查询到sta ip 为target_ip" + sub module: DHCP + summary: dhcp client function test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP client function test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 3 + - ['R SSC1 C +DHCP:AP,OK C +DHCP:STA,OK'] + - - SSC SSC1 dhcp -Q -o 3 + - ['R SSC1 C +DHCP:STA,STARTED C +DHCP:AP,STARTED'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED NC +DHCP:AP,STARTED'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 NC +DHCP:STA,STARTED C +DHCP:AP,STARTED'] + - - SSC SSC1 dhcp -E -o 3 + - ['R SSC1 C +DHCP:AP,OK C +DHCP:STA,OK'] + - - SSC SSC1 dhcp -Q -o 3 + - ['R SSC1 C +DHCP:STA,STOPPED C +DHCP:AP,STOPPED'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.STA&AP STARTED + + 4.STA STARTED + + 5.AP STARTED + + 6.OK + + 7.STA&AP STOPPED' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: TCPIP + steps: '1.target1 设置mode 为sta+softAP mode + + 2.target1 打开DHCP 3 + + 3.target1 查询DHCP 状态 + + 4.target1 查询sta DHCP 状态 + + 5.target1 查询softAP DHCP 状态 + + 6.target1 关闭 DHCP 3 + + 7.target1 查询 DHCP 状态' + sub module: DHCP + summary: dhcp status query + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP client function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -o 2 -i + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.1 -e 192.168.4.10 + - ['R SSC1 C +DHCP:LEASE,ERROR'] + - - SSC SSC1 dhcp -L -s 192.168.4.5 -e 192.168.4.2 + - ['R SSC1 C +DHCP:LEASE,ERROR'] + - - SSC SSC1 dhcp -L -s 192.168.2.2 -e 192.168.2.5 + - ['R SSC1 C +DHCP:LEASE,ERROR'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + comment: '' + execution time: 0.0 + expected result: '1.target1 关闭DHCP 2 OK + + 2.target1 设置ip 成功 + + 3.设置dhcp 地址池 OK + + 4.ERROR + + 5.ERROR + + 6.ERROR + + 7.target1 打开DHCP ok' + initial condition: APM1 + initial condition description (auto): AP mode, DHCP on, will autogen a TC with initial + condition APSTA1 + level: Integration + module: TCPIP + steps: "1.target1 关闭DHCP 2 \n2.target1 设置ip \n3.设置dhcp 地址池\n4.设置dhcp错误的参数\n5.设置dhcp错误的参数\n\ + 6.设置dhcp错误的参数\n7.target1 打开DHCP ok" + sub module: DHCP + summary: server dhcp lease test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0202 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - LOOP 3 4 "['01','02','03']" "[2,3,4]" + - [''] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:{%s} + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.{%s}'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3,4: get IP from dhcp pool with correct sequence' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. config DHCP Server on Target1 + + 3. target change mac, connect to Target1 + + 4. Loop step3' + sub module: DHCP + summary: dhcp server ip pool + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0203 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.3 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - LOOP 2 4 "['01','02']" "[2,3]" + - [''] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:{%s} + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.{%s}'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:66 + - ['R SSC2 C +MAC:STA,OK'] + - - DELAY 20 + - [''] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:0.0.0.0'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4.1 succeed + + 4.2 failed' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. config DHCP Server on Target1(.4.2 - .4.3) + + 3. target change mac, connect to Target1 + + 4. Loop step3 twice' + sub module: DHCP + summary: dhcp server ip pool empty + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0204 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.3 -t 1 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.2'] + - - DELAY 90 + - [''] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.2'] + - - SSC SSC2 sta -D + - ['R SSC2 C +JAP:DISCONNECTED'] + - - DELAY 60 + - [''] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:66 + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.2'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. get IP 192.168.4.2 + + 5. succeed + + 6. succeed + + 8. get IP 192.168.4.2' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. config DHCP timeout as 1 minute + + 3. target2 connect to target1 + + 4. wait 90 seconds + + 5. check if target2 IP is same + + 6. target2 disconnect + + 7. wait 60s + + 8. target2 change mac and connect to target1' + sub module: DHCP + summary: dhcp server timeout test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0205 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.3 -t 1 + - ['P SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['P SSC1 C +DHCP:AP,OK', 'P SSC2 C +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. target2 wifi disconnected' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. target2 connect to target1 + + 3. disable DHCP server, do config and enable' + sub module: DHCP + summary: disconnect STA if config dhcp server + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0206 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - LOOP 4 4 "['01','02','03','01']" "[2,3,4,2]" + - [''] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:{%s} + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.{%s}'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 4. get IP 192.168.4.2 - 192.168.4.4 + + 5. get IP 192.168.4.2' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. disable DHCP server, do config and enable + + 3. target2 change mac, connect to softap, disconnect + + 4. Loop step3 twice + + 5. change to first mac, connect to softap' + sub module: DHCP + summary: dhcp server assign same IP to same MAC when it's not released + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0207 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - WIFI CONN 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - WIFI DISCONN2 + - ['R PC_COM NC ERROR C +WIFIDISCONN:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:66 + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.2'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. get IP 192.168.4.2 + + 4. succeed + + 5. succeed + + 6. get IP 192.168.4.2' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. disable DHCP server, do config and enable + + 3. PC WIFI NIC connect to target1 softap + + 4. target2 connect to target1 softap and disnnect + + 5. PC release IP and disconnected + + 6. target2 change mac and connect to target1' + sub module: DHCP + summary: dhcp server prefer assign released IP to new client + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0208 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['P SSC1 C +DHCP:AP,OK', 'P SSC2 C +JAP:DISCONNECTED'] + - - SSC SSC2 sta -D + - ['R SSC2 C +JAP:DISCONNECTED'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - WIFI CONN 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC1 ap -L + - [R SSC1 C 192.168.4.2 P ] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. get IP 192.168.4.2 + + 5. can only find target2 with IP 192.168.4.2' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. PC NIC connect to target1 softap + + 3. disable DHCP server, do config and enable + + 4. target2 connect to target1 softap + + 5. softap list connected station' + sub module: DHCP + summary: dhcp server reconfig and new client able to get first IP in pool + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0209 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - WIFI CONN 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - DELAY 20 + - [''] + - - SSC SSC1 ap -L + - [R SSC1 C 192.168.4.2 C 192.168.4.3 P P ] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. succeed + + 5. find target2 and PC' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. target2 connect to target1 softap + + 3. disable DHCP server, do config and enable + + 4. PC NIC connect to target1 softap + + 5. softap list connected station' + sub module: DHCP + summary: dhcp server reconfig, old client and new client able to get IP + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0210 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - WIFI CONN2 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC1 ap -L + - [R SSC1 C 192.168.4.2 C 192.168.4.3 P P ] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. succeed + + 5. find target2 and PC' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. target2 connect to target1 softap + + 3. disable DHCP server, do config and enable + + 4. PC NIC connect to target1 softap try to renew IP 192.168.4.2 + + 5. softap list connected station' + sub module: DHCP + summary: dhcp server reconfig, old client able to get IP (discover with requested + IP) + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0211 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - DELAY 30 + - [''] + - - SSC SSC1 ap -L + - [R SSC1 C 192.168.4.2 C 192.168.4.3 P P ] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. succeed + + 5. find target2 and PC' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. target2 connect to target1 softap + + 3. disable DHCP server, do config and enable + + 4. PC NIC connect to target1 softap try to renew IP 192.168.4.2 + + 5. softap list connected station' + sub module: DHCP + summary: dhcp server reconfig, old client able to renew IP (direct send request) + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0212 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 20 + - [P PC_COM C +DELAYDONE, 'P SSC2 NC +JAP:CONNECTED'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: "1.target1 set AP OK \n2.target1 关闭DHCP OK\n3.target2 jap target\ + \ 1,FAIL \n4.target1 打开DHCP OK\n5.target2 jap target 1,ok" + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: "1.target1 set AP OK \n2.target1 关闭DHCP OK\n3.target2 jap target 1,FAIL \n\ + 4.target1 打开DHCP OK\n5.target2 jap target 1,ok" + sub module: DHCP + summary: dhcp server function test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0301 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -i 192.168.123.123 -o 1 + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC1 ip -S -i 0.0.0.0 -o 1 + - [R SSC1 C +IP] + - - SSC SSC1 sta -C -s -p + - [''] + - - DELAY 10 + - [P PC_COM C +DELAYDONE, 'P SSC1 NC +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.JAP CONNETED + + 4.OK + + 5.等待10s,JAP fail' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: TCPIP + steps: '1.target1 关闭DHCP 1 + + 2.target1 设置sta ip 192.168.123.123 + + 4.target1 jap AP + + 5.target1 设置sta ip 0.0.0.0 + + 6.target1 jap AP' + sub module: DHCP + summary: sta dhcp static ip interaction + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: interaction + test point 2: static IP and DHCP interaction test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_DHCP_0302 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -i 192.168.123.123 -o 2 + - ['R SSC1 C +IP:ERROR'] + - - SSC SSC1 dhcp -L -s 192.168.2.2 -e 192.168.2.10 + - ['R SSC1 C +DHCP:LEASE,ERROR'] + - - SSC SSC1 ap -S -s -p -t + - [''] + - - SSC SSC2 sta -C -s -p + - ['P SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -i 192.168.4.1 -o 2 + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.10 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - [P PC_COM C +DELAYDONE, 'P SSC2 NC +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.target 1 OK + + 2.target1 ERROR + + 3.target1 ERROR + + 4.target2 jap target1 OK + + 5.target1 OK + + 6.target1 OK + + 7.target1 OK + + 8.target2 jap target1 OK' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: "1.target1 打开DHCP 2\n2.target1 设置softAP ip 192.168.123.123\n3.target1 设置地址池\n\ + 4.target1下设置ssid 和pwd 加密方式\n5.target2 连接target1 \n6.target1 关闭DHCP 2\n7.target1\ + \ 设置softAP ip \n8.target1 设置正确的地址池\n9.target2 连接target1 " + sub module: DHCP + summary: ap dhcp static ip interaction + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: interaction + test point 2: static IP and DHCP interaction test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DNS_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 3/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -H -d iot.espressif.cn + - ['R SSC1 C +HOSTIP:OK,115.29.202.58'] + comment: '' + execution time: 0.0 + expected result: 1.OK + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: 1. get host name "espressif.cn" + sub module: DNS + summary: get host by name test + test environment: SSC_T1_2 + test environment description (auto): 'Able to access WAN after connect to AP. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DNS function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_DNS_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 3/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -H -d factory.espressif.cn + - ['R SSC1 A :\+HOSTIP:OK,(.+)\r\n'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p 9001 + - ['R SSC1 RE \+CONNECT:\d+,OK'] + - - SSC SSC1 soc -S -s -l 10 + - ['P SSC1 RE \+SEND:\d+,OK', P SSC1 SL +10] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. get host name "espressif.cn" + + 2. connect, send, recv1. get host name "espressif.cn" + + 2. connect, send, recv' + sub module: DNS + summary: TCP connect to iot.espressif.com + test environment: SSC_T1_2 + test environment description (auto): 'Able to access WAN after connect to AP. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DNS function test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_DNS_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 3/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -H -d factory.espressif.cn + - ['R SSC1 A :\+HOSTIP:OK,(.+)\r\n'] + - - SSC SSC1 soc -B -t UDP + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p 9003 -l 10 + - ['P SSC1 RE \+SEND:\d+,OK', P SSC1 SL +10] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. get host name "espressif.cn" + + 2. sendto, recvfrom1. get host name "espressif.cn" + + 2. sendto, recvfrom' + sub module: DNS + summary: UDP send to iot.expressif.com + test environment: SSC_T1_2 + test environment description (auto): 'Able to access WAN after connect to AP. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DNS function test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_ICMP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ping -i + - ['R SSC1 C +PING:OK'] + - - SSC SSC1 ping -i -c 2 + - ['R SSC1 C +PING:OK'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2.ok' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.ping -i + + 2.ping -i -c 2' + sub module: ICMP + summary: ping function test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: ping function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IGMP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -J -h -m 223.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h 192.168.237.77 -m 224.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h 192.168.237.77 -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + comment: '' + execution time: 0.0 + expected result: '1. success + + 2. failed + + 3. failed + + 4. failed' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. join group with correct host addr and multicast addr + + 2. join group with correct host addr and wrong multicast addr + + 3. join group with wrong host addr and correct multicast addr + + 4. join group with wrong host addr and wrong multicast addr' + sub module: IGMP + summary: station IGMP join group address check + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP API parameter check + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IGMP_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -L -h -m 224.1.1.2 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h 192.168.237.77 -m 224.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h 192.168.237.77 -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. success + + 2. failed + + 3. failed + + 4. failed + + 5. succeed' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. join group with correct host addr and multicast addr + + 2. leave group with correct host addr and wrong multicast addr + + 3. leave group with wrong host addr and correct multicast addr + + 4. leave group with wrong host addr and wrong multicast addr + + 5. leave group with correct host addr and correct multicast addr' + sub module: IGMP + summary: station IGMP leave group address check + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP API parameter check + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IGMP_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -J -h -m 223.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h 192.168.237.77 -m 224.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h 192.168.237.77 -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + comment: '' + execution time: 0.0 + expected result: '1. success + + 2. failed + + 3. failed + + 4. failed' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1. join group with correct host addr and multicast addr + + 2. join group with correct host addr and wrong multicast addr + + 3. join group with wrong host addr and correct multicast addr + + 4. join group with wrong host addr and wrong multicast addr' + sub module: IGMP + summary: softAP IGMP join group address check + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP API parameter check + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IGMP_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -L -h -m 224.1.1.2 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h 192.168.237.77 -m 224.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h 192.168.237.77 -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. success + + 2. failed + + 3. failed + + 4. failed + + 5. succeed' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1. join group with correct host addr and multicast addr + + 2. leave group with correct host addr and wrong multicast addr + + 3. leave group with wrong host addr and correct multicast addr + + 4. leave group with wrong host addr and wrong multicast addr + + 5. leave group with correct host addr and correct multicast addr' + sub module: IGMP + summary: softAP IGMP leave group address check + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP API parameter check + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IGMP_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 soc -B -t UDP -i 224.1.1.1 -p + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SOC SOC1 SENDTO 1 224.1.1.1 + - [R SSC1 SL +1] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. able to recv packet' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. join group + + 2. create UDP socket using multicast addr + + 3. PC send UDP packet to multicast addr' + sub module: IGMP + summary: station IGMP recv packets + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP send/recv test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IGMP_0202 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 soc -B -t UDP -i 224.1.1.1 -p + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SSC SSC2 soc -B -t UDP -p + - ['R SSC2 A :\+BIND:(\d+),OK'] + - - SSC SSC2 soc -S -s -i 224.1.1.1 -p -l 10 + - [R SSC1 SL +1] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. target1 recv multicast packet' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. target2 set to sta mode and join AP + + 2. target1 join group and create UDP socket using multicast addr + + 3. target2 create UDP socket + + 4. target2 send to multicast addr' + sub module: IGMP + summary: station send multicast packets + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP send/recv test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IGMP_0203 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 soc -B -t UDP -i 224.1.1.1 -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SOC SOC1 SENDTO 1 224.1.1.1 + - [R SSC1 SL +1] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. able to recv packet' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1. join group + + 2. create UDP socket using multicast addr + + 3. PC send UDP packet to multicast addr' + sub module: IGMP + summary: softAP IGMP recv packets + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP send/recv test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IGMP_0204 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 soc -B -t UDP -i 224.1.1.1 -p + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SSC SSC2 soc -B -t UDP -p + - ['R SSC2 A :\+BIND:(\d+),OK'] + - - SSC SSC2 soc -S -s -i 224.1.1.1 -p -l 10 + - [R SSC1 SL +1] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. target1 recv multicast packet' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: TCPIP + steps: '1. target2 join SoftAP + + 2. target1 join group and create UDP socket using multicast addr + + 3. target2 create UDP socket + + 4. target2 send to multicast addr' + sub module: IGMP + summary: softAP send multicast packets + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP send/recv test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -S -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.123.123 + - ['R SSC1 C +IP:ERROR'] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.123.123 + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.123.123'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.ERROR + + 3.OK + + 4.OK + + 5.STAIP:192.168.123.123' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: TCPIP + steps: '1.target1 打开DHCP 1 + + 2.target1 设置sta ip 192.168.123.123 + + 4.target1 关闭DHCP 1 + + 5.target1 设置sta ip 192.168.123.123 + + 6.target1 查询 当前sta ip ' + sub module: IP + summary: sta set and query static ip test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: set and query static IP + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_IP_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -o 2 -i 192.168.123.123 + - ['R SSC1 C +IP:ERROR'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -o 2 -i 192.168.123.123 + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 ip -Q -o 2 + - ['R SSC1 C +APIP:192.168.123.123'] + - - SSC SSC1 ip -S -o 2 -i + - ['R SSC1 C +IP:OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.ERROR + + 3.OK + + 4.OK + + 5.APIP:192.168.123.123 + + 6.OK' + initial condition: APM1 + initial condition description (auto): AP mode, DHCP on, will autogen a TC with initial + condition APSTA1 + level: Integration + module: TCPIP + steps: "1.target1 打开DHCP 2\n2.target1 设置softAP ip 192.168.123.123\n4.target1 关闭DHCP\ + \ 2\n5.target1 设置softAP ip 192.168.123.123\n6.target1 查询 当前sta ip \n7.target1\ + \ 设置softAP ip 为target_ap_ip" + sub module: IP + summary: ap set and query static ip test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: set and query static IP + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [SOCR SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -i 0.0.0.0 -p 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,OK', P SOC1 C +ACCEPT] + - - SSC SSC1 soc -B -t TCP -i 0.0.0.0 -p 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i 123.456.678.789 -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.ERROR + + 6.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket,bind到本地ip 0.0.0.0,本地端口 0 + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.target1上创建TCP socket,bind到本地ip 0.0.0.0,本地端口 0 + + 5.target1上使用步骤4创建的socket,去连接不存在的ip,test_tcp_port1 + + 6.target1上使用步骤2创建的socket,去连接 PC的ip,远端端口不存在。' + sub module: TCP + summary: STA mode, connect test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC1 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+', P SOC_COM C OK] + - - SOC SOC1 CONNECT + - [P SOC_COM C ERROR, P SSC1 NC ACCEPT] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.PC TCP client accept + + 4.error' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.target1上创建TCP socket,bind到本地端口 + + 2.target1上使用步骤1创建的socket,创建TCP 监听 + + 3.PC TCP 连接到target1 , + + 4.PC tcp 连接到不存在的port ,' + sub module: TCP + summary: STA mode, server listen test. use different kinds of port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SOC SOC2 SEND 5 + - [R SSC1 SL +5] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,OK', P SOC2 RL 5] + - - SOC SOC2 SEND 146000 + - [R SSC1 SL +146000] + - - SSC SSC1 soc -S -s -l 1460 -n 100 + - ['P SSC1 RE SEND:\d+,OK', P SOC2 RL 146000] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc上回accept + + 4.OK + + 5.target收到5 byte + + 6.PC收到5 byte + + 7.target收到 146000 byte + + 8.OK,PC 回SOC_RECV=SOC2,RECV_LEN=字节数' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1 创建好TCP 连接,有ACCEPT + + 5.PC send 5 bytes to 8266 + + 6.8266 send 5 bytes to PC + + 7. PC send 100 * 1460 data to 8266, + + 8.8266 send 100 * 1460 to PC. ' + sub module: TCP + summary: STA mode, send/recv basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h B + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h W + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h R + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept OK + + 4.OK + + 5.OK + + 6.OK,pc tcp server accept OK + + 7.OK + + 8.OK + + 9.OK,pc tcp server accept OK + + 10.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 4.target1 shutdown socket1 B + + 5.target1上创建TCP socket + + 6.target1上使用步骤5创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 7.target1 shutdown socket2 W + + 8.target1上创建TCP socket + + 9.target1上使用步骤8创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 10.target1 shutdown socket3 R' + sub module: TCP + summary: STA mode, shutdown basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0105 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT + - ['R SSC1 A :ACCEPT:(\d+),\d+,.+,\d+'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK + + 6.OK + + 7.target1关闭socket1 + + 8.target1关闭socket2 + + 9.OK + + 10.OK,pc tcp server accept成功 + + 11.target1关闭socket1 + + 12.OK + + 13.OK,pc tcp server accept成功 + + 14.OK + + 15.target1关闭socket1' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1关闭socket1\n\ + 4.target1上创建TCP socket 端口随机\n5.target1上使用步骤4创建的socket1,去监听\n6.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket2 \n7.target1关闭socket1\n8.target1关闭socket2\n\ + 9.target1上创建TCP socket1\n10.target1上使用步骤10创建的socket1,去连接 PC的ip,test_tcp_port1,PC有ACCEPT\n\ + 11.target1关闭socket1\n12.target1上创建TCP socket1\n13.target1上使用步骤13创建的socket1,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n14.target1shutdown socket1\n15.target1关闭socket1" + sub module: TCP + summary: STA mode, close for different types of TCP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0106 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4 OK + + 5.OK,pc tcp server accept成功 + + 6.OK + + 7.OK,pc tcp server accept成功 + + 8 OK + + 9.OK,pc tcp server accept成功 + + 10.OK + + 11.OK,pc tcp server accept成功' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 4.target1上创建TCP socket2 + + 5.target1上使用步骤4创建的socket2,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 6.target1上创建TCP socket3 + + 7.target1上使用步骤6创建的socket3,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 8.target1上创建TCP socket4 + + 9.target1上使用步骤8创建的socket4,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 10.target1上创建TCP socket5 + + 11.target1上使用步骤10创建的socket5,去连接 PC的ip,test_tcp_port1,PC有ACCEPT' + sub module: TCP + summary: STA mode, create max TCP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0107 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC3 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC4 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC5 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC6 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + comment: '' + execution time: 0.0 + expected result: '1.+BIND:0,OK,0.0.0.0 + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK,pc tcp server accept成功 + + 5.OK,pc tcp server accept成功 + + 6.OK,pc tcp server accept成功 + + 7.OK,pc tcp server accept成功' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.target1上创建TCP socket 端口随机\n2.target1上使用步骤4创建的socket1,去监听\n3.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket2 \n4.PC CONNECT, ,tcp 连接创建成功,创建socket3\ + \ \n5.PC CONNECT, ,tcp 连接创建成功,创建socket4 \n6.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket5 \n7.PC CONNECT, ,tcp 连接创建成功,创建socket6\ + \ " + sub module: TCP + summary: STA mode, accept max TCP client by server test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0110 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [SOCR SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -i 0.0.0.0 -p 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,OK', P SOC1 C +ACCEPT] + - - SSC SSC1 soc -B -t TCP -i 0.0.0.0 -p 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i 123.456.678.789 -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.ERROR + + 6.ERROR' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket,bind到本地ip 0.0.0.0,本地端口 0 + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.target1上创建TCP socket,bind到本地ip 0.0.0.0,本地端口 0 + + 5.target1上使用步骤4创建的socket,去连接不存在的ip,test_tcp_port1 + + 6.target1上使用步骤2创建的socket,去连接 PC的ip,远端端口不存在。' + sub module: TCP + summary: AP mode, connect test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0111 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC1 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+', P SOC_COM C OK] + - - SOC SOC1 CONNECT 0 + - [P SOC_COM C ERROR, P SSC1 NC ACCEPT] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.PC TCP client accept + + 4.error' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.target1上创建TCP socket,bind到本地端口 + + 2.target1上使用步骤1创建的socket,创建TCP 监听 + + 3.PC TCP 连接到target1 , + + 4.PC tcp 连接到不存在的port ,' + sub module: TCP + summary: AP mode, server listen test. use different kinds of port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0112 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SOC SOC2 SEND 5 + - [R SSC1 SL +5] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,OK', P SOC2 RL 5] + - - SOC SOC2 SEND 146000 + - [R SSC1 SL +146000] + - - SSC SSC1 soc -S -s -l 1460 -n 100 + - ['P SSC1 RE SEND:\d+,OK', P SOC2 RL 146000] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 5.target收到5byte数据 + + 6.PC收到5byte数据 + + 7.target收到146000 byte数据 + + 8.OK,PC 收到146000 byte数据' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1 创建好TCP 连接,有ACCEPT + + 5.PC send 5 bytes to 8266 + + 6.8266 send 5 bytes to PC + + 7. PC send 100 * 1460 data to 8266, + + 8.8266 send 100 * 1460 to PC. ' + sub module: TCP + summary: AP mode, send/recv basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0113 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h B + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h W + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h R + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 5.OK + + 6.OK,pc tcp server accept成功 + + 7.OK + + 8.OK + + 9.OK,pc tcp server accept成功 + + 10.OK' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 4.target1 shutdown socket1 B + + 5.target1上创建TCP socket + + 6.target1上使用步骤5创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 7.target1 shutdown socket2 W + + 8.target1上创建TCP socket + + 9.target1上使用步骤8创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 10.target1 shutdown socket3 R' + sub module: TCP + summary: AP mode, shutdown basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0114 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT 0 + - ['R SSC1 A :ACCEPT:(\d+),\d+,.+,\d+'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK + + 6.OK,target1上accept 成功 + + 7.target1关闭socket1 + + 8.target1关闭socket2 + + 9.OK + + 10.OK,pc tcp server accept成功 + + 11.target1关闭socket1 + + 12.OK + + 13.OK,pc tcp server accept成功 + + 14.OK + + 15.target1关闭socket1' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1关闭socket1\n\ + 4.target1上创建TCP socket 端口随机\n5.target1上使用步骤4创建的socket1,去监听\n6.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket2 \n7.target1关闭socket1\n8.target1关闭socket2\n\ + 9.target1上创建TCP socket1\n10.target1上使用步骤10创建的socket1,去连接 PC的ip,test_tcp_port1,PC有ACCEPT\n\ + 11.target1关闭socket1\n12.target1上创建TCP socket1\n13.target1上使用步骤13创建的socket1,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n14.target1shutdown socket1\n15.target1关闭socket1" + sub module: TCP + summary: AP mode, close for different types of TCP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0115 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4 OK + + 5.OK,pc tcp server accept成功 + + 6.OK + + 7.OK,pc tcp server accept成功 + + 8 OK + + 9.OK,pc tcp server accept成功 + + 10.OK + + 11.OK,pc tcp server accept成功' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 4.target1上创建TCP socket2 + + 5.target1上使用步骤4创建的socket2,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 6.target1上创建TCP socket3 + + 7.target1上使用步骤6创建的socket3,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 8.target1上创建TCP socket4 + + 9.target1上使用步骤8创建的socket4,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 10.target1上创建TCP socket5 + + 11.target1上使用步骤10创建的socket5,去连接 PC的ip,test_tcp_port1,PC有ACCEPT' + sub module: TCP + summary: AP mode, create max TCP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0116 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC3 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC4 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC5 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC6 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + comment: '' + execution time: 0.0 + expected result: '1.+BIND:0,OK,0.0.0.0 + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK,pc tcp server accept成功 + + 5.OK,pc tcp server accept成功 + + 6.OK,pc tcp server accept成功 + + 7.OK,pc tcp server accept成功' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: "1.target1上创建TCP socket 端口随机\n2.target1上使用步骤4创建的socket1,去监听\n3.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket2 \n4.PC CONNECT, ,tcp 连接创建成功,创建socket3\ + \ \n5.PC CONNECT, ,tcp 连接创建成功,创建socket4 \n6.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket5 \n7.PC CONNECT, ,tcp 连接创建成功,创建socket6\ + \ " + sub module: TCP + summary: AP mode, accept max TCP client by server test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [SOCR SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -i 0.0.0.0 -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h B + - ['P SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2.OK + + 3.ERROR + + 4.OK + + 5.OK + + 6.ERROR + + 7.OK + + 8.OK + + 9.OK + + 10.OK + + 11.OK + + 12.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket,bind到本地ip 0.0.0.0, + + 3.target1上使用步骤2创建的socket,去连接 PC的ip, + + 4.target1上创建TCP socket + + 5.target1上使用步骤4创建的socket,创建TCP 监听 + + 6.target1上使用步骤4创建的socket,去连接 PC的ip, + + 7.target1上创建TCP socket + + 8.target1上使用步骤7创建的socket,去连接 PC的ip, + + 9.target1上关闭步骤7创建的socket + + 10.target1上使用步骤7创建的socket,去连接 PC的ip, + + 11.target1上关闭所有创建的socket + + 12.target1上使用步骤2创建的socket,去连接 PC的ip,' + sub module: TCP + summary: STA mode, connect test. use socket in state that can't connect + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0202 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -L -s 1000 + - ['R SSC1 RE LISTEN:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4.OK + + 5.OK + + 6.ERROR + + 7.OK + + 8.ERROR + + 9.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket,bind到本地ip 0.0.0.0, + + 3.target1上使用步骤2创建的socket,去建立TCP 监听 + + 4.target1上创建TCP socket + + 5.target1上使用步骤4创建的socket,去连接 PC的ip, + + 6.target1上使用步骤4创建的socket,创建TCP 监听 + + 7.target1上shutdown 步骤4的socket + + 8.target1上使用步骤4创建的socket,创建TCP 监听 + + 9.target1上使用不存在socket,创建TCP 监听' + sub module: TCP + summary: STA mode, server listen test. use socket in state that can't listen + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0203 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s + - ['R SSC1 RE SEND:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s + - ['R SSC1 RE SEND:\d+,ERROR'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -S -s + - ['R SSC1 RE SEND:\d+,ERROR'] + - - SSC SSC1 soc -S -s 1000 + - ['R SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4.OK + + 5.ERROR + + 6.OK + + 7.OK + + 8.ERROR + + 9.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket1, + + 3.target1上使用步骤2创建的socket1,去发送数据 + + 4.target1上创建TCP socket2 + + 5.target1上使用步骤4创建的socket2,去发送数据 + + 6.target1上使用步骤4创建的socket2,创建TCP连接,连接成功 + + 7.target1上shutdown 步骤4的socket2 + + 8.target1往socket2发送错误命令发送数据 + + 9.target1上不指定socket往上发送数据' + sub module: TCP + summary: send test. use socket in state that can't send + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0204 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -w 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SOC SOC2 SEND 146000 + - [P SOC_COM R *] + - - SSC SSC1 soc -W -s -o 1 + - ['P SSC1 RE WORKTHREAD:\d+,OK', P SSC1 SL +2920] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc server accept OK + + 4.OK + + 5.OK + + 6.OK + + 7.target收到146000 byte + + ' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1 创建好TCP 连接,有ACCEPT + + 5.target上不进行recv + + 6.PC send 100 * 1460 data to target, + + 7.在target上开始recv' + sub module: TCP + summary: STA mode, recv buffer test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_TCP_0206 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -i + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -i + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT + - ['R SSC1 A :ACCEPT:(\d+),\d+,.+,\d+'] + - - SSC SSC1 soc -I + - ['P SSC1 RE "SOCINFO:%%s,2,%%s,\d+,%%s,%%d"%%(,,,)', + 'P SSC1 RE "SOCINFO:%%s,2,.+,\d+,.+,\d+"%%()', 'P SSC1 RE "SOCINFO:%%s,82,.+,%%d"%%(,)', + 'P SSC1 RE "SOCINFO:%%s,2,%%s,%%d,%%s,\d+"%%(,,,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK + + 8.OK + + 9.PC OK, target1 +ACCEPT:3,2,,port + + 10.+SOCINFO:,,, + + +SOCINFO:,,, + + +SOCINFO:, + + +SOCINFO:,,, + + +SOCINF0ALL' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1,本地ip target_ip\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n4.target1上创建TCP socket2,本地ip target_ip\n5.target1上使用步骤4创建的socket2,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n6.target1 shutdown socket2 \n7.target1上创建TCP\ + \ socket3,本地端口random_port\n8.target1上使用步骤7创建的socket3,去监听\n9.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket4 \n10.target1 查询the socket information" + sub module: TCP + summary: STA mode, get active socket info test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0207 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [SOCR SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -i 0.0.0.0 -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h B + - ['P SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2 OK + + 3.ERROR + + 4.OK + + 5.OK + + 6.ERROR + + 7.OK + + 8.OK + + 9.OK + + 10.OK + + 11.OK + + 12.ERROR' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket,bind到本地ip 0.0.0.0, + + 3.target1上使用步骤2创建的socket,去连接 PC的ip, + + 4.target1上创建TCP socket + + 5.target1上使用步骤4创建的socket,创建TCP 监听 + + 6.target1上使用步骤4创建的socket,去连接 PC的ip, + + 7.target1上创建TCP socket + + 8.target1上使用步骤7创建的socket,去连接 PC的ip, + + 9.target1上关闭步骤7创建的socket + + 10.target1上使用步骤7创建的socket,去连接 PC的ip, + + 11.target1上关闭所有创建的socket + + 12.target1上使用步骤2创建的socket,去连接 PC的ip,' + sub module: TCP + summary: AP mode, connect test. use socket in state that can't connect + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0208 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -L -s 1000 + - ['R SSC1 RE LISTEN:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4 OK + + 5.OK + + 6.ERROR + + 7.OK + + 8.ERROR + + 9.ERROR' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket,bind到本地ip 0.0.0.0, + + 3.target1上使用步骤2创建的socket,去建立TCP 监听 + + 4.target1上创建TCP socket + + 5.target1上使用步骤4创建的socket,去连接 PC的ip, + + 6.target1上使用步骤4创建的socket,创建TCP 监听 + + 7.target1上shutdown 步骤4的socket + + 8.target1上使用步骤4创建的socket,创建TCP 监听 + + 9.target1上使用不存在socket,创建TCP 监听' + sub module: TCP + summary: AP mode, server listen test. use socket in state that can't listen + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0210 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -w 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SOC SOC2 SEND 146000 + - [P SOC_COM R *] + - - SSC SSC1 soc -W -s -o 1 + - ['P SSC1 RE WORKTHREAD:\d+,OK', P SSC1 SL +2920] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 6.OK + + 7.收到 146000 数据 + + ' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1 创建好TCP 连接,有ACCEPT + + 5.target停止调用recv + + 6.PC send 100 * 1460 data to 8266, + + 7.target重新调用recv' + sub module: TCP + summary: AP mode, recv buffer test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_TCP_0212 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -i + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -i + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT 0 + - ['R SSC1 A :ACCEPT:(\d+),\d+,.+,\d+'] + - - SSC SSC1 soc -I + - ['P SSC1 RE "SOCINFO:%%s,2,%%s,\d+,%%s,%%d"%%(,,,)', + 'P SSC1 RE "SOCINFO:%%s,2,.+,\d+,.+,\d+"%%()', 'P SSC1 RE "SOCINFO:%%s,82,.+,%%d"%%(,)', + 'P SSC1 RE "SOCINFO:%%s,2,%%s,%%d,%%s,\d+"%%(,,,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK + + 8.OK + + 9.PC OK, target1 +ACCEPT:3,2,,port + + 10.+SOCINFO:,,, + + +SOCINFO:,,, + + +SOCINFO:, + + +SOCINFO:,,, + + +SOCINF0ALL' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1,本地ip target_ip\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n4.target1上创建TCP socket2,本地ip target_ip\n5.target1上使用步骤4创建的socket2,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n6.target1 shutdown socket2 \n7.target1上创建TCP\ + \ socket3,本地端口random_port\n8.target1上使用步骤7创建的socket3,去监听\n9.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket4 \n10.target1 查询the socket information" + sub module: TCP + summary: AP mode, get active socket info test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0401 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 sta -D + - ['P SSC1 C +QAP:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.断开与AP 连接 + + 6.8266往PC上发送5字节数据' + sub module: TCP + summary: do TCP send after WIFI disconnected + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0402 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 sta -D + - ['P SSC1 C +QAP:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.断开与AP 连接 + + 6.关闭建立的socket1连接' + sub module: TCP + summary: "close TCP socket after WIFI \ndisconnected" + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0403 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 op -S -o 2 + - ['P SSC1 C +MODE:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.修改8266的Mode为softAP mode\ + \ \n6.8266往PC上发送5字节数据" + sub module: TCP + summary: do TCP send after mode changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0404 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 op -S -o 2 + - ['P SSC1 C +MODE:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.修改8266的Mode为softAP mode\ + \ \n6.关闭建立的socket1连接" + sub module: TCP + summary: close TCP socket after mode changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0405 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - NIC DISABLED + - [R PC_COM C OK] + - - SSC SSC1 soc -S -s -l 1 + - [''] + - - DELAY 5400 + - ['P SSC1 RE CLOSED:\d+,0'] + comment: '' + execution time: 1.5 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.TCP连接断开' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.PC 网卡 disable + + 6.target1上使用socket1发送数据,等待 90 分钟' + sub module: TCP + summary: do TCP send after PC NIC disabled + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0406 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - NIC DISABLED + - [R PC_COM C OK] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.PC上网卡禁止掉 \n6.关闭建立的socket1连接" + sub module: TCP + summary: close TCP socket after PC NIC disabled + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0407 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.111.210 + - ['P SSC1 C +IP:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.111.210'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK + + 8.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.关闭8266的DHCP 1\n6.设置sta\ + \ ip \n7.查询sta ip 地址是否生效\n8.8266往PC上发送5字节数据" + sub module: TCP + summary: do TCP send after IP changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0408 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.111.210 + - ['P SSC1 C +IP:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.111.210'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK + + 8.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.关闭8266的DHCP 1\n6.设置sta\ + \ ip \n7.查询sta ip 地址是否生效\n8.关闭建立的socket1连接" + sub module: TCP + summary: close TCP socket after IP changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0411 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.ERROR + + 7.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.target1上创建TCP socket2 + + 6.8266往PC socket2上发送5字节数据 + + 7.8266往PC socket1上发送5字节数据' + sub module: TCP + summary: do TCP send after socket changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_TCP_0412 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.target1上创建TCP socket2 + + 6.关闭socket1 连接 + + 7.关闭socket2连接' + sub module: TCP + summary: close TCP send after socket changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -i 0.0.0.0 -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 C BIND:ERROR'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 RE BIND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上UDP传输,Bind socket2,本地ip 0.0.0.0 target_udp_port2 + + 3.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 4.target1上创建TCP socket3, target_udp_port1' + sub module: UDP + summary: STA mode, udp bind test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SOC SOC2 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 10 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 10] + - - SSC SSC1 soc -S -s -i -p -l 10 + - ['P SSC1 RE SEND:(\d+),OK', P SOC2 UL 10] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.PC上SOC2 UDP传输,bing + + 3.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 4.target1上使用步骤3创建的socket1,往pc_ip,test_tcp_port1上发送10字节数据 + + 5.target1上使用步骤3创建的socket1,往pc_ip2,test_tcp_port2上发送10字节数据' + sub module: UDP + summary: STA mode, sendto test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 1 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 1] + - - SSC SSC1 soc -S -s -i -p -l 1472 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 1472] + - - SSC SSC1 soc -S -s -i -p -l 1473 + - ['P SSC1 RE SEND:(\d+),OK', P SOC_COM NC SOC_RECVFROM] + - - SSC SSC1 soc -S -s -i -p -l 1472 -n 10 -j 20 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 14720] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK,没有到UDP包 + + 6.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1字节数据 + + 4.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1472字节数据 + + 5.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1473字节数据 + + 6.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1472*10字节数据' + sub module: UDP + summary: STA mode, sendto test with different length + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 SENDTO 1 + - [R SSC1 SL +1] + - - SOC SOC1 SENDTO 1472 + - ['R SSC1 RE "RECVFROM:%%s,1472,%%s,%%u"%%(,,)'] + - - SOC SOC1 SENDTO 1473 + - [P SSC1 NC +RECVFROM, P SOC_COM C OK] + - - SOC SOC2 BIND + - [R SOC_COM L OK] + - - SOC SOC2 SENDTO 1472 + - ['R SSC1 RE "RECVFROM:%%s,1472,%%s,%%u"%%(,,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK,没收到UDP包 + + 6.OK + + 7.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.PC往8266上发送1字节数据 + + 4.PC往8266上发送1472字节数据 + + 5.PC往8266上发送1473字节数据 + + 6.PC上SOC2 UDP传输,bing + + 7.PC往8266上发送1472字节数据' + sub module: UDP + summary: STA mode, recvfrom basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0105 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.关闭socket1' + sub module: UDP + summary: STA mode, close UDP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0106 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2.ok + + 3.ok + + 4.ok + + 5.ok' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上UDP传输,Bind socket2,本地ip target_udp_port2 + + 3.target1上UDP传输,Bind socket3,本地ip target_udp_port3 + + 4.target1上UDP传输,Bind socket4,本地ip target_udp_port4 + + 5.target1上UDP传输,Bind socket5,本地ip target_udp_port5' + sub module: UDP + summary: STA mode, create max udp socket test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0107 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -I + - ['P SSC1 RE "SOCINFO:%%s,1,.+,%%d"%%(,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上查询创建socket信息' + sub module: UDP + summary: STA mode, get active socket info test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0108 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -i 0.0.0.0 -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 C BIND:ERROR'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 RE BIND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4.OK' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上UDP传输,Bind socket2,本地ip 0.0.0.0 target_udp_port2 + + 3.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 4.target1上创建TCP socket3, target_udp_port1' + sub module: UDP + summary: AP mode, udp bind test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0109 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC2 ip + - ['R SSC2 A :STAIP:(.+)\r\n'] + - - SSC SSC2 soc -B -t UDP -p + - ['R SSC2 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - [R SOC1 UL 5] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['R SSC2 RE "RECVFROM:%%s,5,%%s,%%u"%%(,,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK' + initial condition: T2O_1 + initial condition description (auto): same as T2_1 but will NOT autogen a TC with + initial condition T2_2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.PC上SOC2 UDP传输,bing + + 3.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 4.target1上使用步骤3创建的socket1,往pc_ip,test_tcp_port1上发送10字节数据 + + 5.target1上使用步骤3创建的socket1,往pc_ip2,test_tcp_port2上发送10字节数据' + sub module: UDP + summary: AP mode, sendto test. use different ip, port + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0110 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 1 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 1] + - - SSC SSC1 soc -S -s -i -p -l 1472 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 1472] + - - SSC SSC1 soc -S -s -i -p -l 1473 + - ['P SSC1 RE SEND:(\d+),OK', P SOC_COM NC SOC_RECVFROM] + - - SSC SSC1 soc -S -s -i -p -l 1472 -n 10 + -j 20 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 14720] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK,没收到UDP包 + + 6.OK' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1字节数据 + + 4.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1472字节数据 + + 5.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1473字节数据 + + 6.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1472*10字节数据' + sub module: UDP + summary: AP mode, sendto test with different length + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0111 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC2 ip + - ['R SSC2 A :STAIP:(.+)\r\n'] + - - SSC SSC2 soc -B -t UDP -p + - ['R SSC2 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 SENDTO 5 + - ['R SSC1 RE "RECVFROM:%%s,5,%%s,%%u"%%(,,)'] + - - SSC SSC2 soc -S -s -i -p -l 5 + - ['R SSC1 RE "RECVFROM:%%s,5,%%s,%%u"%%(,,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK,没收到UDP包 + + 6.OK + + 7.OK' + initial condition: T2O_1 + initial condition description (auto): same as T2_1 but will NOT autogen a TC with + initial condition T2_2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.PC往8266上发送1字节数据 + + 4.PC往8266上发送1472字节数据 + + 5.PC往8266上发送1473字节数据 + + 6.PC上SOC2 UDP传输,bing + + 7.PC往8266上发送1472字节数据' + sub module: UDP + summary: AP mode, recvfrom basic test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0112 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.关闭socket1' + sub module: UDP + summary: AP mode, close UDP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0113 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2.ok + + 3.ok + + 4.ok + + 5.ok' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上UDP传输,Bind socket2,本地ip target_udp_port2 + + 3.target1上UDP传输,Bind socket3,本地ip target_udp_port3 + + 4.target1上UDP传输,Bind socket4,本地ip target_udp_port4 + + 5.target1上UDP传输,Bind socket5,本地ip target_udp_port5' + sub module: UDP + summary: AP mode, create max udp socket test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0114 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -I + - ['P SSC1 RE "SOCINFO:%%s,1,.+,%%d"%%(,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上查询创建socket信息' + sub module: UDP + summary: AP mode, get active socket info test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p -w 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.PC OK + + 5.PC OK + + 6.PC OK + + 7.PC OK + + 8.PC OK SOC_CLOSE=SOC1' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上关闭工作线程 + + 4.PC往8266上发送1472字节数据 + + 5.PC往8266上发送1472字节数据 + + 6.PC往8266上发送1472字节数据 + + 7.PC往8266上发送1472字节数据 + + 8.PC往8266上发送1472字节数据' + sub module: UDP + summary: STA mode, recv buffer test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: use UDP SAP (socket/espconn API) in different state + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_UDP_0202 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.PC OK + + 5.PC OK + + 6.PC OK + + 7.PC OK + + 8.PC OK SOC_CLOSE=SOC1' + initial condition: APM2 + initial condition description (auto): AP mode, PC join AP, DHCP on, will autogen + a TC with initial condition APSTA2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上关闭工作线程 + + 4.PC往8266上发送1472字节数据 + + 5.PC往8266上发送1472字节数据 + + 6.PC往8266上发送1472字节数据 + + 7.PC往8266上发送1472字节数据 + + 8.PC往8266上发送1472字节数据' + sub module: UDP + summary: AP mode, recv buffer test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: use UDP SAP (socket/espconn API) in different state + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: TCPIP_UDP_0301 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -i -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 sta -D + - ['P SSC1 C +QAP:OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据 + + 4.断开与AP 连接 + + 5.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据' + sub module: UDP + summary: do UDP send after WIFI disconnected + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0302 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 sta -D + - ['P SSC1 C +QAP:OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK + + ' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据 + + 4.断开与AP 连接 + + 5.关闭建立的socket1连接' + sub module: UDP + summary: "close UDP socket after WIFI \ndisconnected" + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0303 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 op -S -o 2 + - ['P SSC1 C +MODE:OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.ERROR' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.修改8266的Mode为softAP mode \n5.8266往PC上发送5字节数据" + sub module: UDP + summary: do UDP send after mode changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0304 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 op -S -o 2 + - ['P SSC1 C +MODE:OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.修改8266的Mode为softAP mode \n5.关闭建立的socket1连接" + sub module: UDP + summary: close UDP socket after mode changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0305 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - NIC DISABLED + - [R PC_COM C OK] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.PC上网卡禁止掉 \n5.关闭建立的socket1连接" + sub module: UDP + summary: close UDP socket after PC NIC disabled + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0306 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.111.210 + - ['P SSC1 C +IP:OK'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.111.210'] + - - SSC SSC1 soc -S -s -i -p -l 1 + - ['P SSC1 RE SEND:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.关闭8266的DHCP 1\n5.设置sta ip \n6.查询sta ip 地址是否生效\n7.8266往PC上发送5字节数据" + sub module: UDP + summary: do UDP send after IP changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: TCPIP_UDP_0307 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.111.210 + - ['P SSC1 C +IP:OK'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.111.210'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.关闭8266的DHCP 1\n5.设置sta ip \n6.查询sta ip 地址是否生效\n7.关闭建立的socket1连接" + sub module: UDP + summary: close UDP socket after IP changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_ADDR_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 1 -m 44:55:66:77:88:99 + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 mac -S -o 2 -m 22:33:44:55:66:77 + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 mac -Q -o 3 + - ['R SSC1 C +STAMAC:44:55:66:77:88:99 C +APMAC:22:33:44:55:66:77'] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.ok + + 3.ok + + 4.ok + + 5.ok + + 6.ok' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: "1.target1 设置mode 为sta+softAP mode\n2.target1 设置sta mode 下的mac \n3.target1\ + \ 设置softAP mode 下的mac\n4.target1 查询softAP+sta 下的mac\n5.target1 设置sta mode 下的mac\ + \ 为target1_mac\n6.target1 设置softAP mode 下的mac 为target1_ap_mac\n" + sub module: MAC Address + summary: set mac, query mac + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: mac address function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_ADDR_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 mac -S -o 2 -m 44:55:66:77:88:99 + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - [''] + - - SSC SSC2 sta -S -b 44:55:66:77:88:99 + - ['R SSC2 RE \+SCAN:.+,44:55:66:77:88:99,'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -Q -o 1 + - ['R SSC2 A :\+STAMAC:(.+)\r\n'] + - - SSC SSC2 mac -S -o 1 -m 22:33:44:55:66:77 + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['P SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 ap -L + - ['R SSC1 C +LSTA:22:33:44:55:66:77'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.ok + + 3.ok + + 4.ok + + 5.ok + + 6.ok + + 7.ok + + 8.ok + + 9.ok' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: "1.target1 设置sta mode下的mac 44:55:66:77:88:99\n2.target1下设置ssid 和pwd 加密方式\n\ + 3.target2 查询mac为44:55:66:77:88:99的ssid\n4.target1 设置sta mode下的mac target_ap_mac\n\ + 5.target2 查询sta mode 下的mac 为target2_mac_tmp\n6.target2 设置sta mode 下的mac 为22:33:44:55:66:77\n\ + 7.target2 jap target1\n8.target1 查询连接到的sta \n9.target2 设置sta mode 下的mac 为 target2_mac\n" + sub module: MAC Address + summary: set mac and do scan/JAP/SAP + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: mac address function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -t 0 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -p -t 2 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -p -t 1 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S + - ['R SSC2 RE "\+SCAN:%%s,.+,0,\d+"%%()'] + - - SSC SSC1 ap -S -s -p -t 5 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S + - ['R SSC2 RE "\+SCAN:%%s,.+,0,\d+"%%()'] + comment: '' + execution time: 0.0 + expected result: "1.target1 set AP,open, \n2.target 2 jap succeed\n3.target1 set\ + \ AP,wpa_psk \n4.target 2 jap succeed\n5.target1 set AP, wpa2_psk \n6.target 2\ + \ jap succeed\n7.target1 set AP,wap_wpa2_psk\n8.target 2 jap succeed\n9.target1\ + \ set AP,加密方式为t 1\n10.target 2 上查询到target_ssid\n11.target1 set AP,加密方式为t 5\n12.target\ + \ 2 上查询到target_ssid" + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: "1.target1下设置ssid 和pwd,加密方式 open\n2.target2 jap target1\n3.target1下设置ssid\ + \ 和pwd,加密方式 wpa_psk \n4.target2 jap target1\n5.target1下设置ssid 和pwd,加密方式 wpa2_psk\ + \ \n6.target 2 jap target1\n7.target1下设置ssid 和pwd,加密方式 wap_wpa2_psk\n8.target2\ + \ jap target1\n9.target1下设置ssid 和pwd,加密方式 wep \n10.target2上查询target_ssid\n11.target1下设置ssid\ + \ 和pwd,加密方式 t 5 错误的加密方式\n12.target2上查询 target_ssid" + sub module: WIFI Connect + summary: station SAP+JAP test, different encryption + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: SAP/JAP with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -t 0 -n 1 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -t 0 -n 13 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -n 15 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC2 sta -S + - ['R SSC2 RE "\+SCAN:%%s,.+,\d+,1"%%()'] + comment: '' + execution time: 0.0 + expected result: '1. target1 set AP,set channel 1 + + 2.target 2 jap succeed + + 3.target1 set AP,set channel 10 + + 4.target 2 jap succeed + + 5.target1 set AP,set channel 15 + + 6.target 2 上查询到target_ssid' + initial condition: T2O_1 + initial condition description (auto): same as T2_1 but will NOT autogen a TC with + initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1. target1下设置ssid 和pwd 加密方式,set channel 1 + + 2.target2 jap target 1 + + 3.target1下设置ssid 和pwd 加密方式,set channel 10 + + 4.target2 jap target 1 + + 5.target1下设置ssid 和pwd 加密方式,set channel 15 + + 6.target 2 上查询target_ssid' + sub module: WIFI Connect + summary: station SAP+JAP test, different channel + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: SAP/JAP with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t -h + 0 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 P , R SSC2 C +SCANDONE] + - - SSC SSC1 ap -S -s -p -t -h + 1 + - ['R SSC1 C +SAP:OK'] + - - DELAY 3 + - [''] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 C +SCANDONE] + - - DELAY 3 + - [''] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 NP C +SCANDONE] + comment: '' + execution time: 0.0 + expected result: '1.target1 set AP,set ssid broad cast + + 2.target 2上scan target_ap_mac + + 3.target1 set AP,set ssid hidden, + + 4.target 2上不能scan target_ap_mac' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1. target1下设置ssid 和pwd 加密方式,set ssid broad cast + + 2.target 2上scan target_ap_mac + + 3. target1下设置ssid 和pwd 加密方式,set ssid hidden, + + 4.target 2上scan target_ap_mac' + sub module: WIFI Connect + summary: station SAP+JAP test, ssid hidden + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: SAP/JAP with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t -m + 1 + - ['R SSC1 C +SAP:OK'] + - - WIFI DISCONN + - ['R PC_COM C +WIFIDISCONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - WIFI CONN + + - ['R PC_COM C +WIFICONN:ERROR'] + comment: '' + execution time: 0.0 + expected result: '1. target1 set AP,set max allowed sta as 1 + + 2. use PC disconnect, + + 3.target 2 jap succeed + + 4.PC WIFI can not CONN' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target1下设置ssid 和pwd 加密方式,set max allowed sta as 1 + + 2.use PC disconnect target1 + + 3.target 2 jap target1 + + 4.PC WIFI CONNECT target1' + sub module: WIFI Connect + summary: station SAP test, max allowed sta + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: SAP/JAP with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 sta -Q + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:OK'] + - - SSC SSC1 sta -Q + - ['R SSC1 C +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.target1 jion AP 成功 + + 2.查询JAP的状态 + + 3.target1 断开AP + + 4.查询target1 JAP 是DISCONN' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: WIFI MAC + steps: '1.target1 jion AP 成功 + + 2.查询JAP的状态 + + 3.target1 断开AP + + 4.查询target1 JAP 是DISCONN' + sub module: WIFI Connect + summary: JAP query test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: query JAP status + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0301 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t -h + 0 -m 8 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,3,0,8,\d+"%%(,)'] + comment: '' + execution time: 0.0 + expected result: '1. target1 set AP + + 2.target 1上查询到跟设置AP时一致 + + ' + initial condition: APM1 + initial condition description (auto): AP mode, DHCP on, will autogen a TC with initial + condition APSTA1 + level: Integration + module: WIFI MAC + steps: '1. target1 set AP + + 2.target 1上查询到跟设置AP时一致 + + ' + sub module: WIFI Connect + summary: AP config query test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: query AP config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0401 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -R -a 0 + - ['R SSC1 C +AUTORECONN:OK'] + - - SSC SSC1 sta -R -a 2 + - ['R SSC1 C +AUTORECONN:0'] + - - SSC SSC1 reboot + - [''] + - - DELAY 15 + - [''] + - - SSC SSC1 sta -Q + - ['R SSC1 C JAP:DISCONNECTED'] + - - SSC SSC1 sta -R -a 1 + - ['R SSC1 C +AUTORECONN:OK'] + - - SSC SSC1 sta -R -a 2 + - ['R SSC1 C +AUTORECONN:1'] + - - SSC SSC1 reboot + - ['R SSC1 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.设置autoreconn,关闭 + + 2.查询当前autoreconn状态是否关闭 + + 3.重启系统,等待15s + + 4.查询target1 未自动重连AP + + 5.设置autoreconn,开启 + + 6.查询当前autoreconn状态是否开启 + + 7.系统重启后target1 自动重连AP' + initial condition: STAM2 + initial condition description (auto): sta mode, join AP, DHCP on, will autogen a + TC with initial condition STAAP2 + level: Integration + module: WIFI MAC + steps: '1.设置autoreconn,关闭 + + 2.查询当前autoreconn状态是否关闭 + + 3.重启系统,等待15s + + 4.查询target1 未自动重连AP + + 5.设置autoreconn,开启 + + 6.查询当前autoreconn状态是否开启 + + 7.系统重启后target1 自动重连AP' + sub module: WIFI Connect + summary: auto reconnect test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: power on auto reconnect test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0501 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 sta -R -r 1 + - ['R SSC2 C +RECONN:OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - DELAY 10 + - [''] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - DELAY 15 + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 sta -R -r 0 + - ['R SSC2 C +RECONN:OK'] + - - SSC SSC2 sta -R -r 2 + - ['R SSC2 C +RECONN:0'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - DELAY 10 + - [''] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - DELAY 15 + - [P PC_COM C +DELAYDONE, 'P SSC2 NC +JAP:CONNECTED'] + - - SSC SSC2 sta -R -r 1 + - ['R SSC2 C +RECONN:OK'] + comment: '' + execution time: 0.0 + expected result: '1.设置reconn,开启(此功能不需要重启系统) + + 2.target1 set AP + + 3.target2 JAP target1 成功 + + 4.target2 断开target1 连接 + + 5.等待10s,target2 自动重连target1 + + 6.成功 + + 7.查询reconn状态,关闭 + + 8.修改mode 成功 + + 9.等待15s,target2 不会自动重连target1' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: "1.设置reconn,开启(此功能不需要重启系统)\n2.target1下设置ssid 和pwd 加密方式\n3.target2 JAP target1\ + \ \n4.target1 修改mode 为sta mode\n5.等待10s,target1 修改mode 为softAP mode\n6.设置reconn,关闭\n\ + 7.查询reconn状态,关闭\n8.target1 修改mode 为sta mode\n9.等待15s,target1 修改mode 为softAP mode" + sub module: WIFI Connect + summary: reconnect policy test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: reconnect policy test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0502 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 sta -R -r 1 + - ['R SSC2 C +RECONN:OK'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - DELAY 5 + - ['R SSC2 C +JAP:DISCONNECTED'] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - DELAY 10 + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - DELAY 10 + - [P PC_COM C +DELAYDONE, 'P SSC2 NC +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.target1 set AP + + 2.target2 jap target 1 + + 3.设置reconn,开启(此功能不需要重启系统) + + 4.target2 断开target1 连接 + + 5.等待10s,target2 自动重连target1 + + 6.target2 断开target1 连接' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target1下设置ssid 和pwd 加密方式 + + 2.target2 jap target 1 + + 3.设置reconn,开启(此功能不需要重启系统) + + 4.target2 断开target1 连接 + + 5.等待10s,target2 自动重连target1 + + 6.target2 断开target1 连接' + sub module: WIFI Connect + summary: will not do reconnect after manually disconnected + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: reconnect policy test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0601 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM C +WIFICONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 ap -L + - ['R SSC1 C +LSTA:', 'R SSC1 C +LSTA:', R SSC1 C +LSTADONE] + comment: '' + execution time: 0.0 + expected result: '1.target1 set AP + + 2.PC WIFI CONNECTED + + 3.target2 jap target 1 + + 4.查询到两个sta 连接到target1 上' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1. target1下设置ssid 和pwd 加密方式 + + 2.PC WIFI CONNECTED target1 + + 3.target2 jap target 1 + + 4.查询到两个sta 连接到target1 上' + sub module: WIFI Connect + summary: list stations connected to soft ap test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: list SoftAP connected station + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0801 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 0 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 ap -S -s -p -t 2 + - ['P SSC1 C +SAP:OK', 'P SSC2 C +JAP:AUTHCHANGED,2,0'] + - - SSC SSC1 ap -S -s -p -t 3 + - ['P SSC1 C +SAP:OK', 'P SSC2 C +JAP:AUTHCHANGED,3,2'] + - - SSC SSC1 ap -S -s -p -t 4 + - ['P SSC1 C +SAP:OK', 'P SSC2 C +JAP:AUTHCHANGED,4,3'] + - - SSC SSC1 ap -S -s -p -t 0 + - ['P SSC1 C +SAP:OK', 'P SSC2 C +JAP:AUTHCHANGED,0,4'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. auth change event old mode 0 new mode 2 + + 4. auth change event old mode 2 new mode 3 + + 5. auth change event old mode 3 new mode 4 + + 6. auth change event old mode 4 new mode 0' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1. set target1 softap auth mode 0 + + 2. target2 connect to target1 + + 3. set target1 softap auth mode 2, wait sta connected + + 4. set target1 softap auth mode 3, wait sta connected + + 5. set target1 softap auth mode 4, wait sta connected + + 6. set target1 softap auth mode 0, wait sta connected' + sub module: WIFI Connect + summary: test auth change event + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi auth changed event test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0901 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: basic function + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC1 sta -D + - ['R SSC1 RE JAP:DISCONNECTED,\d+,8'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE JAP:DISCONNECTED,\d+,15'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE JAP:DISCONNECTED,\d+,201'] + comment: '' + execution time: 0.0 + expected result: '1. disconnect event reason REASON_ASSOC_LEAVE + + 2. disconnect event reason REASON_4WAY_HANDSHAKE_TIMEOUT + + 3. disconnect event reason REASON_NO_AP_FOUND' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: WIFI MAC + steps: '1. sta connect to AP, and disconnect + + 2. connect to AP with wrong password + + 3. connect to AP not exist' + sub module: WIFI Connect + summary: test wifi disconnect reason REASON_ASSOC_LEAVE, REASON_4WAY_HANDSHAKE_TIMEOUT, + REASON_NO_AP_FOUND + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi disconnect reason test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0902 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - APC OFF + - [P PC_COM L OK, 'R SSC1 RE JAP:DISCONNECTED,\d+,200'] + - - APC ON + - [P PC_COM L OK] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. disconnect event REASON_BEACON_TIMEOUT' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: WIFI MAC + steps: '1. connect to AP + + 2. AP power off' + sub module: WIFI Connect + summary: test wifi disconnect reason REASON_BEACON_TIMEOUT + test environment: SSC_T1_APC + test environment description (auto): "PC has 1 wired NIC connected to AP.\nPC has\ + \ 1 wired NIC connected to APC (static IP within the same subnet with APC). \n\ + APC control AP power supply. \nPC has 1 WiFi NIC. \n1 SSC target connect with\ + \ PC by UART." + test point 1: basic function + test point 2: wifi disconnect reason test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0903 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p bacfd + - ['R SSC1 RE JAP:DISCONNECTED,\d+,2'] + comment: '' + execution time: 0.0 + expected result: 1. disconect event reason REASON_AUTH_EXPIRE + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: WIFI MAC + steps: 1. connect WEP ap with error password (valid wep password) + sub module: WIFI Connect + summary: test wifi disconnect reason REASON_AUTH_EXPIRE + test environment: SSC_T1_WEP + test environment description (auto): '1 SSC target connect with PC by UART. + + One WEP share key AP placed near SSC1.' + test point 1: basic function + test point 2: wifi disconnect reason test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_CONN_0904 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 3 -m 1 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p 1234567890 + - ['R SSC2 RE JAP:DISCONNECTED,\d+,204'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - WIFI CONN + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE JAP:DISCONNECTED,\d+,5'] + - - WIFI DISCONN + - [P PC_COM C OK, 'R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 ap -S -s -p -t 3 -m 1 + - ['P SSC1 C +SAP:OK', 'P SSC2 RE JAP:DISCONNECTED,\d+,4'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. disconnect event REASON_HANDSHAKE_TIMEOUT + + 3. succeed + + 4. succeed + + 5. disconnect event REASON_ASSOC_TOOMANY + + 6. succeed, target2 connect succeed + + 7. disconnect event REASON_ASSOC_EXPIRE' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1. config target1 softap max sta allowed 1 + + 2. target2 connect to target1 with wrong password + + 3. target2 disconnect + + 4. PC WIFI NIC connect to target1 + + 5. target2 connect to target1 with correct password + + 6. PC WIFI NIC disconnect + + 7. reconfig softap' + sub module: WIFI Connect + summary: test wifi disconnect reason REASON_ASSOC_TOOMANY, REASON_HANDSHAKE_TIMEOUT, + REASON_ASSOC_EXPIRE + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi disconnect reason test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_MODE_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC2 sta -S + - [R SSC2 NP C +SCANDONE] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:OK'] + comment: '' + execution time: 0.0 + expected result: '1.target1下设置ssid 和pwd 、加密方式成功 + + 2.修改target 1的mode 为sta mode + + 3.target1的dhcp打开 + + 4.target1成功连接上AP + + 5.target2上不能查询到target_ssid + + 6.target1断开AP' + initial condition: T2O_1 + initial condition description (auto): same as T2_1 but will NOT autogen a TC with + initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target1下设置ssid 和pwd 加密方式 + + 2.修改target1的mode 为sta mode + + 3.target1的dhcp打开 + + 4.target1连接AP + + 5.target2查询target_ssid + + 6.target1断开AP' + sub module: WIFI Mode + summary: mode switch test (sta mode) + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi mode fucntion + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_MODE_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S + - [R SSC2 P , R SSC2 C +SCANDONE] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:ERROR'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:ERROR'] + comment: '' + execution time: 0.0 + expected result: '1. target1 set AP + + 2.target 2 上查询到target_ssid + + 3. target1 can''t join AP + + 4. target1 can''t QAP' + initial condition: T2O_1 + initial condition description (auto): same as T2_1 but will NOT autogen a TC with + initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target1下设置ssid 和pwd 加密方式 + + 2.target 2 上查询target_ssid + + 3.target1 join AP + + 4.target1 DISCONN AP' + sub module: WIFI Mode + summary: mode switch test (AP mode) + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi mode fucntion + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_MODE_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -S -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC2 sta -S + - [R SSC2 P , R SSC2 C +SCANDONE] + comment: '' + execution time: 0.0 + expected result: '1.target1 change to AP mode + + 2.target1 set AP + + 3.target 1 的dhcp 打开 + + 4.target 1 成功连接上AP + + 5.target 2 上查询到target_ssid' + initial condition: T2O_1 + initial condition description (auto): same as T2_1 but will NOT autogen a TC with + initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target1 change to AP mode + + 2.target1下设置ssid 和pwd 加密方式 + + 3.target1 的dhcp 打开 + + 4.target1 连接AP + + 5.target2 上查询target_ssid' + sub module: WIFI Mode + summary: mode switch test (STA+AP mode) + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi mode fucntion + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0401 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 phy -S -o 1 -m n -b 20 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC1 NC +JAP:DISCONNECTED', 'P SSC2 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: 3. SoftAP and STA in channel2, both bandwidth 20M, STA not disconnected + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. SoftAP 11n ht20, in channel1, ext AP 11n ht20, in channel2 + + 2. STA connect to ext AP + + 3. AP get connected' + sub module: Phy Mode + summary: SoftAP ext AP in defferent channel, both bandwidth 20M, STA connect to + AP then Softap get connected + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP initial channel test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0402 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 phy -S -o 1 -m n -b 20 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['P SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 NC +JAP:DISCONNECTED', 'P SSC1 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: 3. SoftAP and STA in channel2, both bandwidth 20M, SoftAP not get + disconnected + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. SoftAP 11n ht20, in channel1, ext AP 11n ht20, in channel2 + + 2. AP get connected + + 3. STA connect to ext AP' + sub module: Phy Mode + summary: SoftAP ext AP in defferent channel, both bandwidth 20M, Softap get connected + than STA connect to AP + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP initial channel test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0403 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 phy -S -o 1 -m n -b 20 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC1 NC +JAP:DISCONNECTED', 'P SSC2 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: 3. SoftAP and STA in channel2, SoftAP 20M, STA 40M, STA not disconnected + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. SoftAP 11n ht20, in channel1, ext AP 11n ht40, in channel2 + + 2. STA connect to ext AP + + 3. AP get connected' + sub module: Phy Mode + summary: SoftAP ext AP in defferent channel, SoftAP 20M, ext AP 40M, STA connect + to AP then Softap get connected + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP initial channel test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0404 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 phy -S -o 1 -m n -b 20 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['P SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 NC +JAP:DISCONNECTED', 'P SSC1 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: 3. SoftAP and STA in channel2, SoftAP 20M, STA 40M, SoftAP not + get disconnected + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. SoftAP 11n ht20, in channel1, ext AP 11n ht40, in channel2 + + 2. AP get connected + + 3. STA connect to ext AP' + sub module: Phy Mode + summary: SoftAP ext AP in defferent channel, SoftAP 20M, ext AP 40M, Softap get + connected than STA connect to AP + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP initial channel test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0405 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 phy -S -o 1 -m n -b 40 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC1 NC +JAP:DISCONNECTED', 'P SSC2 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: 3. SoftAP and STA in channel2, both bandwidth 40M, STA not disconnected + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. SoftAP 11n ht40, in channel1, ext AP 11n ht40, in channel2 + + 2. STA connect to ext AP + + 3. AP get connected' + sub module: Phy Mode + summary: SoftAP ext AP in defferent channel, both bandwidth 40M, STA connect to + AP then Softap get connected + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP initial channel test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0406 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 phy -S -o 1 -m n -b 40 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['P SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 NC +JAP:DISCONNECTED', 'P SSC1 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: 3. SoftAP and STA in channel2, both bandwidth 40M, SoftAP not get + disconnected + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. SoftAP 11n ht40, in channel1, ext AP 11n ht40, in channel2 + + 2. AP get connected + + 3. STA connect to ext AP' + sub module: Phy Mode + summary: SoftAP ext AP in defferent channel, both bandwidth 40M, Softap get connected + than STA connect to AP + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP initial channel test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0407 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 phy -S -o 1 -m n -b 40 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC1 NC +JAP:DISCONNECTED', 'P SSC2 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: 3. SoftAP and STA in channel2, SoftAP 40M, STA 20M, STA not disconnected + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. SoftAP 11n ht40, in channel1, ext AP 11n ht20, in channel2 + + 2. STA connect to ext AP + + 3. AP get connected' + sub module: Phy Mode + summary: SoftAP ext AP in defferent channel, SoftAP 40M, ext AP 20M, STA connect + to AP then Softap get connected + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP initial channel test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0408 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 phy -S -o 1 -m n -b 40 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['P SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 NC +JAP:DISCONNECTED', 'P SSC1 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: 3. SoftAP and STA in channel2, SoftAP 40M, STA 20M, SoftAP not + get disconnected + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. SoftAP 11n ht40, in channel1, ext AP 11n ht20, in channel2 + + 2. AP get connected + + 3. STA connect to ext AP' + sub module: Phy Mode + summary: SoftAP ext AP in defferent channel, SoftAP 40M, ext AP 20M, Softap get + connected than STA connect to AP + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP initial channel test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0501 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC3 sta -C -s -p + - ['R SSC3 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 C +JAP:CONNECTED', 'P SSC[1,3] NC +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: 4. all STA not get disconnected; target 1 SoftAP and STA both in + channel2 20M + initial condition: T3_PHY1 + initial condition description (auto): '1. target 1 and target 2 set to AP+STA mode, + target 3 set to STA mode + + 2. all interface of target 2,3 set to 11n ht40 + + 3. config softAP of target 1 and target 2' + level: Integration + module: WIFI MAC + steps: '1. target 1 STA and SoftAP set to 20M + + 2. target 2 STA connect to ap_channel1_20 + + 3. target 1/3 STA connect to target 2/1 SoftAP + + 4. target 2 STA connect to ap_channel2_20' + sub module: Phy Mode + summary: SoftAP STA in channel1 20M, STA changed to channel2 20M + test environment: SSC_T3_PhyMode + test environment description (auto): '3 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP dynamic channel switch test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0502 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC3 sta -C -s -p + - ['R SSC3 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 C +JAP:CONNECTED', 'P SSC[1,3] NC +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: 4. all STA not get disconnected; target 1 SoftAP and STA both in + channel2; SoftAP in 20M, STA in 40M + initial condition: T3_PHY1 + initial condition description (auto): '1. target 1 and target 2 set to AP+STA mode, + target 3 set to STA mode + + 2. all interface of target 2,3 set to 11n ht40 + + 3. config softAP of target 1 and target 2' + level: Integration + module: WIFI MAC + steps: '1. target 1 STA set to 40M, SoftAP set to 20M + + 2. target 2 STA connect to ap_channel1_20 + + 3. target 1/3 STA connect to target 2/1 SoftAP + + 4. target 2 STA connect to ap_channel2_40' + sub module: Phy Mode + summary: SoftAP STA in channel1 20M, STA changed to channel2 40M + test environment: SSC_T3_PhyMode + test environment description (auto): '3 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP dynamic channel switch test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0503 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC3 sta -C -s -p + - ['R SSC3 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 C +JAP:CONNECTED', 'P SSC[1,3] NC +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: 4. all STA not get disconnected; target 1 SoftAP and STA both in + channel2 20M + initial condition: T3_PHY1 + initial condition description (auto): '1. target 1 and target 2 set to AP+STA mode, + target 3 set to STA mode + + 2. all interface of target 2,3 set to 11n ht40 + + 3. config softAP of target 1 and target 2' + level: Integration + module: WIFI MAC + steps: '1. target 1 STA set to 40M, SoftAP set to 20M + + 2. target 2 STA connect to ap_channel1_40 + + 3. target 1/3 STA connect to target 2/1 SoftAP + + 4. target 2 STA connect to ap_channel2_20' + sub module: Phy Mode + summary: SoftAP STA in channel1, SoftAP 20M, STA 40M, STA changed to channel2 20M + test environment: SSC_T3_PhyMode + test environment description (auto): '3 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP dynamic channel switch test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0504 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC3 sta -C -s -p + - ['R SSC3 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 C +JAP:CONNECTED', 'P SSC[1,3] NC +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: 4. all STA not get disconnected; target 1 SoftAP and STA both in + channel2 20M + initial condition: T3_PHY1 + initial condition description (auto): '1. target 1 and target 2 set to AP+STA mode, + target 3 set to STA mode + + 2. all interface of target 2,3 set to 11n ht40 + + 3. config softAP of target 1 and target 2' + level: Integration + module: WIFI MAC + steps: '1. target 1 STA and SoftAP set to 40M + + 2. target 2 STA connect to ap_channel1_40 + + 3. target 1/3 STA connect to target 2/1 SoftAP + + 4. target 2 STA connect to ap_channel2_20' + sub module: Phy Mode + summary: SoftAP STA in channel1, SoftAP 20M, STA 40M, STA changed to channel2 40M + test environment: SSC_T3_PhyMode + test environment description (auto): '3 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP dynamic channel switch test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0505 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC3 sta -C -s -p + - ['R SSC3 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 C +JAP:CONNECTED', 'P SSC[1,3] NC +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: 4. all STA not get disconnected; target 1 SoftAP and STA both in + channel2; SoftAP in 20M, STA in 40M + initial condition: T3_PHY1 + initial condition description (auto): '1. target 1 and target 2 set to AP+STA mode, + target 3 set to STA mode + + 2. all interface of target 2,3 set to 11n ht40 + + 3. config softAP of target 1 and target 2' + level: Integration + module: WIFI MAC + steps: '1. target 1 STA set to 40M ,SoftAP set to 20M + + 2. target 2 STA connect to ap_channel1_40 + + 3. target 1/3 STA connect to target 2/1 SoftAP + + 4. target 2 STA connect to ap_channel2_20' + sub module: Phy Mode + summary: SoftAP STA in channel1, SoftAP 40M, STA 40M, STA changed to channel2 20M + test environment: SSC_T3_PhyMode + test environment description (auto): '3 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP dynamic channel switch test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_PHY_0506 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 phy -S -o 2 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC3 sta -C -s -p + - ['R SSC3 C +JAP:CONNECTED'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - ['P SSC2 C +JAP:CONNECTED', 'P SSC[1,3] NC +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: 4. all STA not get disconnected; target 1 SoftAP and STA both in + channel2 40M + initial condition: T3_PHY1 + initial condition description (auto): '1. target 1 and target 2 set to AP+STA mode, + target 3 set to STA mode + + 2. all interface of target 2,3 set to 11n ht40 + + 3. config softAP of target 1 and target 2' + level: Integration + module: WIFI MAC + steps: '1. target 1 STA and SoftAP set to 40M + + 2. target 2 STA connect to ap_channel1_40 + + 3. target 1/3 STA connect to target 2/1 SoftAP + + 4. target 2 STA connect to ap_channel2_40' + sub module: Phy Mode + summary: SoftAP STA in channel1, SoftAP 40M, STA 40M, STA changed to channel2 40M + test environment: SSC_T3_PhyMode + test environment description (auto): '3 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: STA+SoftAP dynamic channel switch test + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 sta -S -s .,juhg123 + - ['R SSC2 NC +SCAN: C +SCANDONE'] + - - SSC SSC1 ap -S -s -p 123456789 -t 3 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -s + - ['R SSC2 C +SCAN:', R SSC2 P , 'R SSC2 NC +SCAN: C +SCANDONE'] + comment: '' + execution time: 0.0 + expected result: '1.target 2上不能scan .,juhg123 + + 2.target1 set AP + + 3.target2上查询到' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target 2 scan .,juhg123 + + 2.target1下设置ssid 和pwd 加密方式 + + 3.target2 scan ' + sub module: WIFI Scan + summary: scan with scan config ssid + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 sta -S -b ff:ff:ff:ff:ff:11 + - ['R SSC2 NC +SCAN: C +SCANDONE'] + - - SSC SSC2 sta -S -b + - ['R SSC2 RE "\+SCAN:.+,%%s"%%()', 'R SSC2 NC +SCAN: C +SCANDONE'] + comment: '' + execution time: 0.0 + expected result: '1.target2 上不能查询到此mac + + 2.target2上查询到' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target2 上查询此macff:ff:ff:ff:ff:11 + + 2.target2上查询' + sub module: WIFI Scan + summary: scan with scan config bssid + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 ap -S -s -p 123456789 -t 3 -n 6 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -n 5 + - [R SSC2 NP C +SCANDONE] + - - SSC SSC2 sta -S -n 6 + - ['R SSC2 C +SCAN:', R SSC2 P ] + comment: '' + execution time: 0.0 + expected result: '1.target1 QAP + + 2. target1 set AP,set channel 6 + + 3.target2 上scan不到 channel 5 + + 4.target2 上查询channel 6的' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target1 断开连接AP + + 2.target1下设置ssid 和pwd 加密方式,set channel 6 + + 3.target2 上scan channel 5 + + 4.target2 上查询channel 6的' + sub module: WIFI Scan + summary: scan with scan config channel + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p 123456789 -t 3 -h 0 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 P C +SCANDONE] + - - SSC SSC2 sta -S -h 1 + - [R SSC2 P C +SCANDONE] + - - SSC SSC1 ap -S -s -p 123456789 -h 1 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 NP C +SCANDONE] + - - SSC SSC2 sta -S -h 1 + - [R SSC2 P C +SCANDONE] + comment: '' + execution time: 0.0 + expected result: '1.target1 set AP,set ssid broad cast + + 2.target 2上scan + + 3.target 2上scan + + 4.target1 set AP,set ssid hidden, + + 5.target 2上不能查询到 + + 6.target 2上查询到' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target1下设置ssid 和pwd 加密方式,set ssid broad cast + + 2.target 2上scan + + 3.target 2上scan + + 4.target1下设置ssid 和pwd 加密方式,set ssid hidden, + + 5.target 2上查询 + + 6.target 2上查询' + sub module: WIFI Scan + summary: scan with scan config show hidden + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0105 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 ap -S -s -p 123456789 -t 3 -h 0 -n 11 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -s -b -n 11 + - [R SSC2 P C +SCANDONE] + - - SSC SSC2 sta -S -s -b -n 11 + - [R SSC2 NP C +SCANDONE] + - - SSC SSC2 sta -S -s -b ff:ff:ff:ff:ff:11 -n 11 + - [R SSC2 P , R SSC2 NP C +SCANDONE] + - - SSC SSC2 sta -S -s -b -n 10 + - [R SSC2 P , R SSC2 NP C +SCANDONE] + comment: '' + execution time: 0.0 + expected result: '1.target1 QAP + + 2. target1 set AP,set ssid broad cast,set channel 11 + + 3.target2 上查询到 + + 4.target2 上查询不到 + + 5.target2 上查询不到 + + 6.target2 上查询不到' + initial condition: T2_1 + initial condition description (auto): target 1 as SoftAP, target 2 as STA, will + autogen a TC with initial condition T2_2 + level: Integration + module: WIFI MAC + steps: '1.target1 QAP + + 2. target1 set AP,set ssid broad cast,set channel 11 + + 3.target2 上查询到 + + 4.target2 上查询不到 + + 5.target2 上查询不到 + + 6.target2 上查询不到' + sub module: WIFI Scan + summary: scan with several configs + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0201 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 phy -S -o 1 -m b + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 sta -S + - [R SSC1 P P P P ] + - - SSC SSC1 phy -S -o 1 -m g + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 sta -S + - [R SSC1 P P P P ] + - - SSC SSC1 phy -S -o 1 -m n -b 20 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 sta -S + - [R SSC1 P P P P ] + - - SSC SSC1 phy -S -o 1 -m n -b 40 + - ['R SSC1 C +PHY:OK'] + - - SSC SSC1 sta -S + - [R SSC1 P P P P ] + comment: '' + execution time: 0.0 + expected result: '3. find all 3 ext APs + + 5. find all 3 ext APs + + 7. find all 3 ext APs + + 9. find all 3 ext APs' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: WIFI MAC + steps: '1. 3 ext APs in 11b, 11g, 11n mode + + 2. STA in 11b mode + + 3. do all channel scan + + 4. STA in 11g mode + + 5. do all channel scan + + 6. STA in 11n ht20 mode + + 7. do all channel scan + + 8. STA in 11n ht40 mode + + 9. do all channel scan' + sub module: WIFI Scan + summary: STA in differnt PHY mode to scan AP in different PHY mode + test environment: SSC_T2_PhyMode + test environment description (auto): '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.' + test point 1: basic function + test point 2: Scan in different mode and channel + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0301 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -S + - [''] + - - SSC SSC1 sta -S + - [P SSC1 C +SCANFAIL, 'P SSC1 C +SCAN:', R SSC1 C +SCANDONE] + comment: '' + execution time: 0.0 + expected result: '1. second scan failed + + 2. first scan succeed' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: WIFI MAC + steps: '1. do all channel scan + + 2. do scan before scan finished' + sub module: WIFI Scan + summary: reject scan request before scan finished + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: interaction + test point 2: Scan interact with other WiFi operation + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0302 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -n 1000000 -j 5 + - [''] + - - SSC SSC2 phy -S -o 1 -m b + - ['R SSC2 C +PHY:OK'] + - - SSC SSC2 sta -S -n + - [R SSC2 P ] + - - SSC SSC2 phy -S -o 1 -m g + - ['R SSC2 C +PHY:OK'] + - - SSC SSC2 sta -S -n + - [R SSC2 P ] + - - SSC SSC2 phy -S -o 1 -m n -b 20 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC2 sta -S -n + - [R SSC2 P ] + - - SSC SSC2 phy -S -o 1 -m n -b 40 + - ['R SSC2 C +PHY:OK'] + - - SSC SSC2 sta -S -n + - [R SSC2 P ] + comment: '' + execution time: 0.0 + expected result: 3. target 2 able to scan AP + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. target 1 connect to AP + + 2. target 1 start sending UDP packets + + 3. target 2 scan in AP channel in 11b.g,n,ht40 mode' + sub module: WIFI Scan + summary: scan in congest channel + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: interaction + test point 2: Scan interact with other WiFi operation + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0303 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:OK'] + - - SSC SSC1 sta -S + - [P SSC1 C +SCANDONE, 'P SSC1 C +JAP:CONNECTED'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:OK'] + - - SSC SSC1 sta -S + - [''] + - - SSC SSC1 sta -C -s -p + - [P SSC1 C +SCANDONE, 'P SSC1 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '2. scan succeed, JAP succeed + + 5. JAP succeed, scan succeed' + initial condition: STAM1 + initial condition description (auto): sta mode, quit AP, DHCP on, will autogen a + TC with initial condition STAAP1 + level: Integration + module: WIFI MAC + steps: '1. target 1 STA join AP + + 2. target 1 STA scan before JAP succeed + + 3. target 1 quite AP + + 4. target 1 scan + + 5. target 1 JAP before scan succeed' + sub module: WIFI Scan + summary: scan during JAP + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: interaction + test point 2: Scan interact with other WiFi operation + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: WIFI_SCAN_0304 + SDK: ESP32_IDF + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:OK'] + - - SSC SSC1 sta -S + - [P SSC1 C +SCANDONE, 'P SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC1 sta -S + - [''] + - - SSC SSC2 sta -C -s -p + - [P SSC1 C +SCANDONE, 'P SSC2 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '2. scan succeed, JAP succeed + + 5. JAP succeed, scan succeed' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. target 2 STA join target 1 SoftAP + + 2. target 1 STA scan before target 2 JAP succeed + + 3. target 2 STA QAP + + 4. target 1 STA scan + + 5. target 2 STA JAP before target 1 STA scan succeed' + sub module: WIFI Scan + summary: scan during ext STA join SoftAP + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: interaction + test point 2: Scan interact with other WiFi operation + version: v1 (2015-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -i 0.0.0.0 + - [R SSC1 C +IP] + - - SSC SSC1 sta -C -s -p + - [''] + - - DELAY 20 + - [P PC_COM C +DELAYDONE, 'P SSC1 NC +JAP:CONNECTED'] + - - SSC SSC1 dhcp -S -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -Q + - ['R SSC1 C +STAIP:0.0.0.0'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC1 ip -Q + - ['R SSC1 RE "\+STAIP:%%s"%%()'] + comment: '' + execution time: 0.0 + expected result: "1.target1 关闭DHCP OK\n2.target1 设置ip add OK\n3.target1 连接AP fail\n\ + 4.target1 打开DHCP OK\n5.查询到sta ip \n6.target1 连接AP ok\n7.查询到sta ip 为target_ip" + initial condition: STAAP1 + initial condition description (auto): testing sta on sta + ap mode, quit AP (autogen + by STAM1) + level: Integration + module: TCPIP + steps: "1.target1 关闭DHCP OK\n2.target1 设置ip add OK\n3.target1 连接AP fail\n4.target1\ + \ 打开DHCP OK\n5.查询到sta ip \n6.target1 连接AP ok\n7.查询到sta ip 为target_ip" + sub module: DHCP + summary: dhcp client function test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP client function test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 3 + - ['R SSC1 C +DHCP:AP,OK C +DHCP:STA,OK'] + - - SSC SSC1 dhcp -Q -o 3 + - ['R SSC1 C +DHCP:STA,STARTED C +DHCP:AP,STARTED'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED NC +DHCP:AP,STARTED'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 NC +DHCP:STA,STARTED C +DHCP:AP,STARTED'] + - - SSC SSC1 dhcp -E -o 3 + - ['R SSC1 C +DHCP:AP,OK C +DHCP:STA,OK'] + - - SSC SSC1 dhcp -Q -o 3 + - ['R SSC1 C +DHCP:STA,STOPPED C +DHCP:AP,STOPPED'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.STA&AP STARTED + + 4.STA STARTED + + 5.AP STARTED + + 6.OK + + 7.STA&AP STOPPED' + initial condition: STAAP1 + initial condition description (auto): testing sta on sta + ap mode, quit AP (autogen + by STAM1) + level: Integration + module: TCPIP + steps: '1.target1 设置mode 为sta+softAP mode + + 2.target1 打开DHCP 3 + + 3.target1 查询DHCP 状态 + + 4.target1 查询sta DHCP 状态 + + 5.target1 查询softAP DHCP 状态 + + 6.target1 关闭 DHCP 3 + + 7.target1 查询 DHCP 状态' + sub module: DHCP + summary: dhcp status query + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP client function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -o 2 -i + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.1 -e 192.168.4.10 + - ['R SSC1 C +DHCP:LEASE,ERROR'] + - - SSC SSC1 dhcp -L -s 192.168.4.5 -e 192.168.4.2 + - ['R SSC1 C +DHCP:LEASE,ERROR'] + - - SSC SSC1 dhcp -L -s 192.168.2.2 -e 192.168.2.5 + - ['R SSC1 C +DHCP:LEASE,ERROR'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + comment: '' + execution time: 0.0 + expected result: '1.target1 关闭DHCP 2 OK + + 2.target1 设置ip 成功 + + 3.设置dhcp 地址池 OK + + 4.ERROR + + 5.ERROR + + 6.ERROR + + 7.target1 打开DHCP ok' + initial condition: APSTA1 + initial condition description (auto): testing ap on sta + ap mode (autogen by APM1) + level: Integration + module: TCPIP + steps: "1.target1 关闭DHCP 2 \n2.target1 设置ip \n3.设置dhcp 地址池\n4.设置dhcp错误的参数\n5.设置dhcp错误的参数\n\ + 6.设置dhcp错误的参数\n7.target1 打开DHCP ok" + sub module: DHCP + summary: server dhcp lease test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0202 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - LOOP 3 4 "['01','02','03']" "[2,3,4]" + - [''] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:{%s} + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.{%s}'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3,4: get IP from dhcp pool with correct sequence' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. config DHCP Server on Target1 + + 3. target change mac, connect to Target1 + + 4. Loop step3' + sub module: DHCP + summary: dhcp server ip pool + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0203 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.3 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - LOOP 2 4 "['01','02']" "[2,3]" + - [''] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:{%s} + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.{%s}'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:66 + - ['R SSC2 C +MAC:STA,OK'] + - - DELAY 20 + - [''] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:0.0.0.0'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4.1 succeed + + 4.2 failed' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. config DHCP Server on Target1(.4.2 - .4.3) + + 3. target change mac, connect to Target1 + + 4. Loop step3 twice' + sub module: DHCP + summary: dhcp server ip pool empty + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0204 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.3 -t 1 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.2'] + - - DELAY 90 + - [''] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.2'] + - - SSC SSC2 sta -D + - ['R SSC2 C +JAP:DISCONNECTED'] + - - DELAY 60 + - [''] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:66 + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.2'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. get IP 192.168.4.2 + + 5. succeed + + 6. succeed + + 8. get IP 192.168.4.2' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. config DHCP timeout as 1 minute + + 3. target2 connect to target1 + + 4. wait 90 seconds + + 5. check if target2 IP is same + + 6. target2 disconnect + + 7. wait 60s + + 8. target2 change mac and connect to target1' + sub module: DHCP + summary: dhcp server timeout test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0205 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.3 -t 1 + - ['P SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['P SSC1 C +DHCP:AP,OK', 'P SSC2 C +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. target2 wifi disconnected' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. target2 connect to target1 + + 3. disable DHCP server, do config and enable' + sub module: DHCP + summary: disconnect STA if config dhcp server + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0206 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - LOOP 4 4 "['01','02','03','01']" "[2,3,4,2]" + - [''] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:{%s} + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.{%s}'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 4. get IP 192.168.4.2 - 192.168.4.4 + + 5. get IP 192.168.4.2' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. disable DHCP server, do config and enable + + 3. target2 change mac, connect to softap, disconnect + + 4. Loop step3 twice + + 5. change to first mac, connect to softap' + sub module: DHCP + summary: dhcp server assign same IP to same MAC when it's not released + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0207 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - WIFI CONN 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - WIFI DISCONN2 + - ['R PC_COM NC ERROR C +WIFIDISCONN:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - SSC SSC2 mac -S -o 1 -m 10:22:33:44:55:66 + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 ip -Q -o 1 + - ['R SSC2 C +STAIP:192.168.4.2'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. get IP 192.168.4.2 + + 4. succeed + + 5. succeed + + 6. get IP 192.168.4.2' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. disable DHCP server, do config and enable + + 3. PC WIFI NIC connect to target1 softap + + 4. target2 connect to target1 softap and disnnect + + 5. PC release IP and disconnected + + 6. target2 change mac and connect to target1' + sub module: DHCP + summary: dhcp server prefer assign released IP to new client + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0208 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['P SSC1 C +DHCP:AP,OK', 'P SSC2 C +JAP:DISCONNECTED'] + - - SSC SSC2 sta -D + - ['R SSC2 C +JAP:DISCONNECTED'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - WIFI CONN 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC1 ap -L + - [R SSC1 C 192.168.4.2 P ] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. get IP 192.168.4.2 + + 5. can only find target2 with IP 192.168.4.2' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. PC NIC connect to target1 softap + + 3. disable DHCP server, do config and enable + + 4. target2 connect to target1 softap + + 5. softap list connected station' + sub module: DHCP + summary: dhcp server reconfig and new client able to get first IP in pool + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0209 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - WIFI CONN 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - DELAY 20 + - [''] + - - SSC SSC1 ap -L + - [R SSC1 C 192.168.4.2 C 192.168.4.3 P P ] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. succeed + + 5. find target2 and PC' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. target2 connect to target1 softap + + 3. disable DHCP server, do config and enable + + 4. PC NIC connect to target1 softap + + 5. softap list connected station' + sub module: DHCP + summary: dhcp server reconfig, old client and new client able to get IP + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0210 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - WIFI CONN2 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC1 ap -L + - [R SSC1 C 192.168.4.2 C 192.168.4.3 P P ] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. succeed + + 5. find target2 and PC' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. target2 connect to target1 softap + + 3. disable DHCP server, do config and enable + + 4. PC NIC connect to target1 softap try to renew IP 192.168.4.2 + + 5. softap list connected station' + sub module: DHCP + summary: dhcp server reconfig, old client able to get IP (discover with requested + IP) + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0211 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN 192.168.4.2 + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.100 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - DELAY 30 + - [''] + - - SSC SSC1 ap -L + - [R SSC1 C 192.168.4.2 C 192.168.4.3 P P ] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. succeed + + 5. find target2 and PC' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. config softap to a random ssid + + 2. target2 connect to target1 softap + + 3. disable DHCP server, do config and enable + + 4. PC NIC connect to target1 softap try to renew IP 192.168.4.2 + + 5. softap list connected station' + sub module: DHCP + summary: dhcp server reconfig, old client able to renew IP (direct send request) + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0212 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 20 + - [P PC_COM C +DELAYDONE, 'P SSC2 NC +JAP:CONNECTED'] + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: "1.target1 set AP OK \n2.target1 关闭DHCP OK\n3.target2 jap target\ + \ 1,FAIL \n4.target1 打开DHCP OK\n5.target2 jap target 1,ok" + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: "1.target1 set AP OK \n2.target1 关闭DHCP OK\n3.target2 jap target 1,FAIL \n\ + 4.target1 打开DHCP OK\n5.target2 jap target 1,ok" + sub module: DHCP + summary: dhcp server function test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DHCP server function test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0301 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -i 192.168.123.123 -o 1 + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC1 ip -S -i 0.0.0.0 -o 1 + - [R SSC1 C +IP] + - - SSC SSC1 sta -C -s -p + - [''] + - - DELAY 10 + - [P PC_COM C +DELAYDONE, 'P SSC1 NC +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.JAP CONNETED + + 4.OK + + 5.等待10s,JAP fail' + initial condition: STAAP1 + initial condition description (auto): testing sta on sta + ap mode, quit AP (autogen + by STAM1) + level: Integration + module: TCPIP + steps: '1.target1 关闭DHCP 1 + + 2.target1 设置sta ip 192.168.123.123 + + 4.target1 jap AP + + 5.target1 设置sta ip 0.0.0.0 + + 6.target1 jap AP' + sub module: DHCP + summary: sta dhcp static ip interaction + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: interaction + test point 2: static IP and DHCP interaction test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_DHCP_0302 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -i 192.168.123.123 -o 2 + - ['R SSC1 C +IP:ERROR'] + - - SSC SSC1 dhcp -L -s 192.168.2.2 -e 192.168.2.10 + - ['R SSC1 C +DHCP:LEASE,ERROR'] + - - SSC SSC1 ap -S -s -p -t + - [''] + - - SSC SSC2 sta -C -s -p + - ['P SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -i 192.168.4.1 -o 2 + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 dhcp -L -s 192.168.4.2 -e 192.168.4.10 + - ['R SSC1 C +DHCP:LEASE,OK'] + - - SSC SSC2 sta -C -s -p + - [''] + - - DELAY 10 + - [P PC_COM C +DELAYDONE, 'P SSC2 NC +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.target 1 OK + + 2.target1 ERROR + + 3.target1 ERROR + + 4.target2 jap target1 OK + + 5.target1 OK + + 6.target1 OK + + 7.target1 OK + + 8.target2 jap target1 OK' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: "1.target1 打开DHCP 2\n2.target1 设置softAP ip 192.168.123.123\n3.target1 设置地址池\n\ + 4.target1下设置ssid 和pwd 加密方式\n5.target2 连接target1 \n6.target1 关闭DHCP 2\n7.target1\ + \ 设置softAP ip \n8.target1 设置正确的地址池\n9.target2 连接target1" + sub module: DHCP + summary: ap dhcp static ip interaction + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: interaction + test point 2: static IP and DHCP interaction test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DNS_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 3/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -H -d iot.espressif.cn + - ['R SSC1 C +HOSTIP:OK,115.29.202.58'] + comment: '' + execution time: 0.0 + expected result: 1.OK + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: 1. get host name "espressif.cn" + sub module: DNS + summary: get host by name test + test environment: SSC_T1_2 + test environment description (auto): 'Able to access WAN after connect to AP. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DNS function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_DNS_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 3/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -H -d factory.espressif.cn + - ['R SSC1 A :\+HOSTIP:OK,(.+)\r\n'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p 9001 + - ['R SSC1 RE \+CONNECT:\d+,OK'] + - - SSC SSC1 soc -S -s -l 10 + - ['P SSC1 RE \+SEND:\d+,OK', P SSC1 SL +10] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. get host name "espressif.cn" + + 2. connect, send, recv1. get host name "espressif.cn" + + 2. connect, send, recv' + sub module: DNS + summary: TCP connect to iot.espressif.com + test environment: SSC_T1_2 + test environment description (auto): 'Able to access WAN after connect to AP. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DNS function test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_DNS_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 3/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -H -d factory.espressif.cn + - ['R SSC1 A :\+HOSTIP:OK,(.+)\r\n'] + - - SSC SSC1 soc -B -t UDP + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p 9003 -l 10 + - ['P SSC1 RE \+SEND:\d+,OK', P SSC1 SL +10] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. get host name "espressif.cn" + + 2. sendto, recvfrom1. get host name "espressif.cn" + + 2. sendto, recvfrom' + sub module: DNS + summary: UDP send to iot.expressif.com + test environment: SSC_T1_2 + test environment description (auto): 'Able to access WAN after connect to AP. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: DNS function test + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_ICMP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ping -i + - ['R SSC1 C +PING:OK'] + - - SSC SSC1 ping -i -c 2 + - ['R SSC1 C +PING:OK'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2.ok' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.ping -i + + 2.ping -i -c 2' + sub module: ICMP + summary: ping function test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: ping function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IGMP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -J -h -m 223.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h 192.168.237.77 -m 224.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h 192.168.237.77 -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + comment: '' + execution time: 0.0 + expected result: '1. success + + 2. failed + + 3. failed + + 4. failed' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. join group with correct host addr and multicast addr + + 2. join group with correct host addr and wrong multicast addr + + 3. join group with wrong host addr and correct multicast addr + + 4. join group with wrong host addr and wrong multicast addr' + sub module: IGMP + summary: station IGMP join group address check + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP API parameter check + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IGMP_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -L -h -m 224.1.1.2 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h 192.168.237.77 -m 224.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h 192.168.237.77 -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. success + + 2. failed + + 3. failed + + 4. failed + + 5. succeed' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. join group with correct host addr and multicast addr + + 2. leave group with correct host addr and wrong multicast addr + + 3. leave group with wrong host addr and correct multicast addr + + 4. leave group with wrong host addr and wrong multicast addr + + 5. leave group with correct host addr and correct multicast addr' + sub module: IGMP + summary: station IGMP leave group address check + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP API parameter check + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IGMP_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -J -h -m 223.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h 192.168.237.77 -m 224.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -J -h 192.168.237.77 -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + comment: '' + execution time: 0.0 + expected result: '1. success + + 2. failed + + 3. failed + + 4. failed' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1. join group with correct host addr and multicast addr + + 2. join group with correct host addr and wrong multicast addr + + 3. join group with wrong host addr and correct multicast addr + + 4. join group with wrong host addr and wrong multicast addr' + sub module: IGMP + summary: softAP IGMP join group address check + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP API parameter check + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IGMP_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 igmp -L -h -m 224.1.1.2 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h 192.168.237.77 -m 224.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h 192.168.237.77 -m 240.1.1.1 + - ['R SSC1 C +IGMP:ERROR'] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. success + + 2. failed + + 3. failed + + 4. failed + + 5. succeed' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1. join group with correct host addr and multicast addr + + 2. leave group with correct host addr and wrong multicast addr + + 3. leave group with wrong host addr and correct multicast addr + + 4. leave group with wrong host addr and wrong multicast addr + + 5. leave group with correct host addr and correct multicast addr' + sub module: IGMP + summary: softAP IGMP leave group address check + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP API parameter check + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IGMP_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 soc -B -t UDP -i 224.1.1.1 -p + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SOC SOC1 SENDTO 1 224.1.1.1 + - [R SSC1 SL +1] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. able to recv packet' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. join group + + 2. create UDP socket using multicast addr + + 3. PC send UDP packet to multicast addr' + sub module: IGMP + summary: station IGMP recv packets + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP send/recv test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IGMP_0202 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 soc -B -t UDP -i 224.1.1.1 -p + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SSC SSC2 soc -B -t UDP -p + - ['R SSC2 A :\+BIND:(\d+),OK'] + - - SSC SSC2 soc -S -s -i 224.1.1.1 -p -l 10 + - [R SSC1 SL +1] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. target1 recv multicast packet' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. target2 set to sta mode and join AP + + 2. target1 join group and create UDP socket using multicast addr + + 3. target2 create UDP socket + + 4. target2 send to multicast addr' + sub module: IGMP + summary: station send multicast packets + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP send/recv test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IGMP_0203 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 soc -B -t UDP -i 224.1.1.1 -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SOC SOC1 SENDTO 1 224.1.1.1 + - [R SSC1 SL +1] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. able to recv packet' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1. join group + + 2. create UDP socket using multicast addr + + 3. PC send UDP packet to multicast addr' + sub module: IGMP + summary: softAP IGMP recv packets + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP send/recv test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IGMP_0204 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 igmp -J -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + - - SSC SSC1 soc -B -t UDP -i 224.1.1.1 -p + - ['R SSC1 A :\+BIND:(\d+),OK'] + - - SSC SSC2 soc -B -t UDP -p + - ['R SSC2 A :\+BIND:(\d+),OK'] + - - SSC SSC2 soc -S -s -i 224.1.1.1 -p -l 10 + - [R SSC1 SL +1] + - - SSC SSC1 igmp -L -h -m 224.1.1.1 + - ['R SSC1 C +IGMP:OK'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. succeed + + 4. target1 recv multicast packet' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: TCPIP + steps: '1. target2 join SoftAP + + 2. target1 join group and create UDP socket using multicast addr + + 3. target2 create UDP socket + + 4. target2 send to multicast addr' + sub module: IGMP + summary: softAP send multicast packets + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: IGMP send/recv test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -S -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.123.123 + - ['R SSC1 C +IP:ERROR'] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.123.123 + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.123.123'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.ERROR + + 3.OK + + 4.OK + + 5.STAIP:192.168.123.123' + initial condition: STAAP1 + initial condition description (auto): testing sta on sta + ap mode, quit AP (autogen + by STAM1) + level: Integration + module: TCPIP + steps: '1.target1 打开DHCP 1 + + 2.target1 设置sta ip 192.168.123.123 + + 4.target1 关闭DHCP 1 + + 5.target1 设置sta ip 192.168.123.123 + + 6.target1 查询 当前sta ip' + sub module: IP + summary: sta set and query static ip test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: set and query static IP + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_IP_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 dhcp -S -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -o 2 -i 192.168.123.123 + - ['R SSC1 C +IP:ERROR'] + - - SSC SSC1 dhcp -E -o 2 + - ['R SSC1 C +DHCP:AP,OK'] + - - SSC SSC1 ip -S -o 2 -i 192.168.123.123 + - ['R SSC1 C +IP:OK'] + - - SSC SSC1 ip -Q -o 2 + - ['R SSC1 C +APIP:192.168.123.123'] + - - SSC SSC1 ip -S -o 2 -i + - ['R SSC1 C +IP:OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.ERROR + + 3.OK + + 4.OK + + 5.APIP:192.168.123.123 + + 6.OK' + initial condition: APSTA1 + initial condition description (auto): testing ap on sta + ap mode (autogen by APM1) + level: Integration + module: TCPIP + steps: "1.target1 打开DHCP 2\n2.target1 设置softAP ip 192.168.123.123\n4.target1 关闭DHCP\ + \ 2\n5.target1 设置softAP ip 192.168.123.123\n6.target1 查询 当前sta ip \n7.target1\ + \ 设置softAP ip 为target_ap_ip" + sub module: IP + summary: ap set and query static ip test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: set and query static IP + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [SOCR SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -i 0.0.0.0 -p 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,OK', P SOC1 C +ACCEPT] + - - SSC SSC1 soc -B -t TCP -i 0.0.0.0 -p 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i 123.456.678.789 -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.ERROR + + 6.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket,bind到本地ip 0.0.0.0,本地端口 0 + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.target1上创建TCP socket,bind到本地ip 0.0.0.0,本地端口 0 + + 5.target1上使用步骤4创建的socket,去连接不存在的ip,test_tcp_port1 + + 6.target1上使用步骤2创建的socket,去连接 PC的ip,远端端口不存在。' + sub module: TCP + summary: STA mode, connect test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC1 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+', P SOC_COM C OK] + - - SOC SOC1 CONNECT + - [P SOC_COM C ERROR, P SSC1 NC ACCEPT] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.PC TCP client accept + + 4.error' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.target1上创建TCP socket,bind到本地端口 + + 2.target1上使用步骤1创建的socket,创建TCP 监听 + + 3.PC TCP 连接到target1 , + + 4.PC tcp 连接到不存在的port ,' + sub module: TCP + summary: STA mode, server listen test. use different kinds of port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SOC SOC2 SEND 5 + - [R SSC1 SL +5] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,OK', P SOC2 RL 5] + - - SOC SOC2 SEND 146000 + - [R SSC1 SL +146000] + - - SSC SSC1 soc -S -s -l 1460 -n 100 + - ['P SSC1 RE SEND:\d+,OK', P SOC2 RL 146000] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc上回accept + + 4.OK + + 5.target收到5 byte + + 6.PC收到5 byte + + 7.target收到 146000 byte + + 8.OK,PC 回SOC_RECV=SOC2,RECV_LEN=字节数' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1 创建好TCP 连接,有ACCEPT + + 5.PC send 5 bytes to 8266 + + 6.8266 send 5 bytes to PC + + 7. PC send 100 * 1460 data to 8266, + + 8.8266 send 100 * 1460 to PC.' + sub module: TCP + summary: STA mode, send/recv basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h B + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h W + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h R + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept OK + + 4.OK + + 5.OK + + 6.OK,pc tcp server accept OK + + 7.OK + + 8.OK + + 9.OK,pc tcp server accept OK + + 10.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 4.target1 shutdown socket1 B + + 5.target1上创建TCP socket + + 6.target1上使用步骤5创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 7.target1 shutdown socket2 W + + 8.target1上创建TCP socket + + 9.target1上使用步骤8创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 10.target1 shutdown socket3 R' + sub module: TCP + summary: STA mode, shutdown basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0105 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT + - ['R SSC1 A :ACCEPT:(\d+),\d+,.+,\d+'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK + + 6.OK + + 7.target1关闭socket1 + + 8.target1关闭socket2 + + 9.OK + + 10.OK,pc tcp server accept成功 + + 11.target1关闭socket1 + + 12.OK + + 13.OK,pc tcp server accept成功 + + 14.OK + + 15.target1关闭socket1' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1关闭socket1\n\ + 4.target1上创建TCP socket 端口随机\n5.target1上使用步骤4创建的socket1,去监听\n6.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket2 \n7.target1关闭socket1\n8.target1关闭socket2\n\ + 9.target1上创建TCP socket1\n10.target1上使用步骤10创建的socket1,去连接 PC的ip,test_tcp_port1,PC有ACCEPT\n\ + 11.target1关闭socket1\n12.target1上创建TCP socket1\n13.target1上使用步骤13创建的socket1,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n14.target1shutdown socket1\n15.target1关闭socket1" + sub module: TCP + summary: STA mode, close for different types of TCP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0106 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4 OK + + 5.OK,pc tcp server accept成功 + + 6.OK + + 7.OK,pc tcp server accept成功 + + 8 OK + + 9.OK,pc tcp server accept成功 + + 10.OK + + 11.OK,pc tcp server accept成功' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 4.target1上创建TCP socket2 + + 5.target1上使用步骤4创建的socket2,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 6.target1上创建TCP socket3 + + 7.target1上使用步骤6创建的socket3,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 8.target1上创建TCP socket4 + + 9.target1上使用步骤8创建的socket4,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 10.target1上创建TCP socket5 + + 11.target1上使用步骤10创建的socket5,去连接 PC的ip,test_tcp_port1,PC有ACCEPT' + sub module: TCP + summary: STA mode, create max TCP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0107 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC3 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC4 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC5 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC6 CONNECT + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + comment: '' + execution time: 0.0 + expected result: '1.+BIND:0,OK,0.0.0.0 + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK,pc tcp server accept成功 + + 5.OK,pc tcp server accept成功 + + 6.OK,pc tcp server accept成功 + + 7.OK,pc tcp server accept成功' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.target1上创建TCP socket 端口随机\n2.target1上使用步骤4创建的socket1,去监听\n3.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket2 \n4.PC CONNECT, ,tcp 连接创建成功,创建socket3\ + \ \n5.PC CONNECT, ,tcp 连接创建成功,创建socket4 \n6.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket5 \n7.PC CONNECT, ,tcp 连接创建成功,创建socket6" + sub module: TCP + summary: STA mode, accept max TCP client by server test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0110 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [SOCR SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -i 0.0.0.0 -p 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,OK', P SOC1 C +ACCEPT] + - - SSC SSC1 soc -B -t TCP -i 0.0.0.0 -p 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i 123.456.678.789 -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.ERROR + + 6.ERROR' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket,bind到本地ip 0.0.0.0,本地端口 0 + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.target1上创建TCP socket,bind到本地ip 0.0.0.0,本地端口 0 + + 5.target1上使用步骤4创建的socket,去连接不存在的ip,test_tcp_port1 + + 6.target1上使用步骤2创建的socket,去连接 PC的ip,远端端口不存在。' + sub module: TCP + summary: AP mode, connect test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0111 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC1 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+', P SOC_COM C OK] + - - SOC SOC1 CONNECT 0 + - [P SOC_COM C ERROR, P SSC1 NC ACCEPT] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.PC TCP client accept + + 4.error' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.target1上创建TCP socket,bind到本地端口 + + 2.target1上使用步骤1创建的socket,创建TCP 监听 + + 3.PC TCP 连接到target1 , + + 4.PC tcp 连接到不存在的port ,' + sub module: TCP + summary: AP mode, server listen test. use different kinds of port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0112 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SOC SOC2 SEND 5 + - [R SSC1 SL +5] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,OK', P SOC2 RL 5] + - - SOC SOC2 SEND 146000 + - [R SSC1 SL +146000] + - - SSC SSC1 soc -S -s -l 1460 -n 100 + - ['P SSC1 RE SEND:\d+,OK', P SOC2 RL 146000] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 5.target收到5byte数据 + + 6.PC收到5byte数据 + + 7.target收到146000 byte数据 + + 8.OK,PC 收到146000 byte数据' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1 创建好TCP 连接,有ACCEPT + + 5.PC send 5 bytes to 8266 + + 6.8266 send 5 bytes to PC + + 7. PC send 100 * 1460 data to 8266, + + 8.8266 send 100 * 1460 to PC.' + sub module: TCP + summary: AP mode, send/recv basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0113 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h B + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h W + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h R + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 5.OK + + 6.OK,pc tcp server accept成功 + + 7.OK + + 8.OK + + 9.OK,pc tcp server accept成功 + + 10.OK' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 4.target1 shutdown socket1 B + + 5.target1上创建TCP socket + + 6.target1上使用步骤5创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 7.target1 shutdown socket2 W + + 8.target1上创建TCP socket + + 9.target1上使用步骤8创建的socket,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 10.target1 shutdown socket3 R' + sub module: TCP + summary: AP mode, shutdown basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0114 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT 0 + - ['R SSC1 A :ACCEPT:(\d+),\d+,.+,\d+'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK + + 6.OK,target1上accept 成功 + + 7.target1关闭socket1 + + 8.target1关闭socket2 + + 9.OK + + 10.OK,pc tcp server accept成功 + + 11.target1关闭socket1 + + 12.OK + + 13.OK,pc tcp server accept成功 + + 14.OK + + 15.target1关闭socket1' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1关闭socket1\n\ + 4.target1上创建TCP socket 端口随机\n5.target1上使用步骤4创建的socket1,去监听\n6.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket2 \n7.target1关闭socket1\n8.target1关闭socket2\n\ + 9.target1上创建TCP socket1\n10.target1上使用步骤10创建的socket1,去连接 PC的ip,test_tcp_port1,PC有ACCEPT\n\ + 11.target1关闭socket1\n12.target1上创建TCP socket1\n13.target1上使用步骤13创建的socket1,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n14.target1shutdown socket1\n15.target1关闭socket1" + sub module: TCP + summary: AP mode, close for different types of TCP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0115 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4 OK + + 5.OK,pc tcp server accept成功 + + 6.OK + + 7.OK,pc tcp server accept成功 + + 8 OK + + 9.OK,pc tcp server accept成功 + + 10.OK + + 11.OK,pc tcp server accept成功' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 4.target1上创建TCP socket2 + + 5.target1上使用步骤4创建的socket2,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 6.target1上创建TCP socket3 + + 7.target1上使用步骤6创建的socket3,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 8.target1上创建TCP socket4 + + 9.target1上使用步骤8创建的socket4,去连接 PC的ip,test_tcp_port1,PC有ACCEPT + + 10.target1上创建TCP socket5 + + 11.target1上使用步骤10创建的socket5,去连接 PC的ip,test_tcp_port1,PC有ACCEPT' + sub module: TCP + summary: AP mode, create max TCP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0116 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC3 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC4 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC5 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + - - SOC SOC6 CONNECT 0 + - ['R SSC1 RE ACCEPT:(\d+),\d+,.+,\d+'] + comment: '' + execution time: 0.0 + expected result: '1.+BIND:0,OK,0.0.0.0 + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK,pc tcp server accept成功 + + 5.OK,pc tcp server accept成功 + + 6.OK,pc tcp server accept成功 + + 7.OK,pc tcp server accept成功' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: "1.target1上创建TCP socket 端口随机\n2.target1上使用步骤4创建的socket1,去监听\n3.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket2 \n4.PC CONNECT, ,tcp 连接创建成功,创建socket3\ + \ \n5.PC CONNECT, ,tcp 连接创建成功,创建socket4 \n6.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket5 \n7.PC CONNECT, ,tcp 连接创建成功,创建socket6" + sub module: TCP + summary: AP mode, accept max TCP client by server test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [SOCR SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -i 0.0.0.0 -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h B + - ['P SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2.OK + + 3.ERROR + + 4.OK + + 5.OK + + 6.ERROR + + 7.OK + + 8.OK + + 9.OK + + 10.OK + + 11.OK + + 12.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket,bind到本地ip 0.0.0.0, + + 3.target1上使用步骤2创建的socket,去连接 PC的ip, + + 4.target1上创建TCP socket + + 5.target1上使用步骤4创建的socket,创建TCP 监听 + + 6.target1上使用步骤4创建的socket,去连接 PC的ip, + + 7.target1上创建TCP socket + + 8.target1上使用步骤7创建的socket,去连接 PC的ip, + + 9.target1上关闭步骤7创建的socket + + 10.target1上使用步骤7创建的socket,去连接 PC的ip, + + 11.target1上关闭所有创建的socket + + 12.target1上使用步骤2创建的socket,去连接 PC的ip,' + sub module: TCP + summary: STA mode, connect test. use socket in state that can't connect + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0202 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -L -s 1000 + - ['R SSC1 RE LISTEN:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4.OK + + 5.OK + + 6.ERROR + + 7.OK + + 8.ERROR + + 9.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket,bind到本地ip 0.0.0.0, + + 3.target1上使用步骤2创建的socket,去建立TCP 监听 + + 4.target1上创建TCP socket + + 5.target1上使用步骤4创建的socket,去连接 PC的ip, + + 6.target1上使用步骤4创建的socket,创建TCP 监听 + + 7.target1上shutdown 步骤4的socket + + 8.target1上使用步骤4创建的socket,创建TCP 监听 + + 9.target1上使用不存在socket,创建TCP 监听' + sub module: TCP + summary: STA mode, server listen test. use socket in state that can't listen + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0203 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s + - ['R SSC1 RE SEND:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s + - ['R SSC1 RE SEND:\d+,ERROR'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -S -s + - ['R SSC1 RE SEND:\d+,ERROR'] + - - SSC SSC1 soc -S -s 1000 + - ['R SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4.OK + + 5.ERROR + + 6.OK + + 7.OK + + 8.ERROR + + 9.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket1, + + 3.target1上使用步骤2创建的socket1,去发送数据 + + 4.target1上创建TCP socket2 + + 5.target1上使用步骤4创建的socket2,去发送数据 + + 6.target1上使用步骤4创建的socket2,创建TCP连接,连接成功 + + 7.target1上shutdown 步骤4的socket2 + + 8.target1往socket2发送错误命令发送数据 + + 9.target1上不指定socket往上发送数据' + sub module: TCP + summary: send test. use socket in state that can't send + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0204 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -w 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SOC SOC2 SEND 146000 + - [P SOC_COM R *] + - - SSC SSC1 soc -W -s -o 1 + - ['P SSC1 RE WORKTHREAD:\d+,OK', P SSC1 SL +2920] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc server accept OK + + 4.OK + + 5.OK + + 6.OK + + 7.target收到146000 byte' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1 创建好TCP 连接,有ACCEPT + + 5.target上不进行recv + + 6.PC send 100 * 1460 data to target, + + 7.在target上开始recv' + sub module: TCP + summary: STA mode, recv buffer test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0206 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -i + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -i + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT + - ['R SSC1 A :ACCEPT:(\d+),\d+,.+,\d+'] + - - SSC SSC1 soc -I + - ['P SSC1 RE "SOCINFO:%%s,2,%%s,\d+,%%s,%%d"%%(,,,)', + 'P SSC1 RE "SOCINFO:%%s,2,.+,\d+,.+,\d+"%%()', 'P SSC1 RE "SOCINFO:%%s,82,.+,%%d"%%(,)', + 'P SSC1 RE "SOCINFO:%%s,2,%%s,%%d,%%s,\d+"%%(,,,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK + + 8.OK + + 9.PC OK, target1 +ACCEPT:3,2,,port + + 10.+SOCINFO:,,, + + +SOCINFO:,,, + + +SOCINFO:, + + +SOCINFO:,,, + + +SOCINF0ALL' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1,本地ip target_ip\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n4.target1上创建TCP socket2,本地ip target_ip\n5.target1上使用步骤4创建的socket2,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n6.target1 shutdown socket2 \n7.target1上创建TCP\ + \ socket3,本地端口random_port\n8.target1上使用步骤7创建的socket3,去监听\n9.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket4 \n10.target1 查询the socket information" + sub module: TCP + summary: STA mode, get active socket info test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0207 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [SOCR SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -i 0.0.0.0 -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s -h B + - ['P SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 soc -C -s -i -p + - ['P SSC1 RE CONNECT:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2 OK + + 3.ERROR + + 4.OK + + 5.OK + + 6.ERROR + + 7.OK + + 8.OK + + 9.OK + + 10.OK + + 11.OK + + 12.ERROR' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket,bind到本地ip 0.0.0.0, + + 3.target1上使用步骤2创建的socket,去连接 PC的ip, + + 4.target1上创建TCP socket + + 5.target1上使用步骤4创建的socket,创建TCP 监听 + + 6.target1上使用步骤4创建的socket,去连接 PC的ip, + + 7.target1上创建TCP socket + + 8.target1上使用步骤7创建的socket,去连接 PC的ip, + + 9.target1上关闭步骤7创建的socket + + 10.target1上使用步骤7创建的socket,去连接 PC的ip, + + 11.target1上关闭所有创建的socket + + 12.target1上使用步骤2创建的socket,去连接 PC的ip,' + sub module: TCP + summary: AP mode, connect test. use socket in state that can't connect + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0208 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,ERROR'] + - - SSC SSC1 soc -L -s 1000 + - ['R SSC1 RE LISTEN:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4 OK + + 5.OK + + 6.ERROR + + 7.OK + + 8.ERROR + + 9.ERROR' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建UDP传输socket,bind到本地ip 0.0.0.0, + + 3.target1上使用步骤2创建的socket,去建立TCP 监听 + + 4.target1上创建TCP socket + + 5.target1上使用步骤4创建的socket,去连接 PC的ip, + + 6.target1上使用步骤4创建的socket,创建TCP 监听 + + 7.target1上shutdown 步骤4的socket + + 8.target1上使用步骤4创建的socket,创建TCP 监听 + + 9.target1上使用不存在socket,创建TCP 监听' + sub module: TCP + summary: AP mode, server listen test. use socket in state that can't listen + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0210 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -w 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SOC SOC2 SEND 146000 + - [P SOC_COM R *] + - - SSC SSC1 soc -W -s -o 1 + - ['P SSC1 RE WORKTHREAD:\d+,OK', P SSC1 SL +2920] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 6.OK + + 7.收到 146000 数据' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1. PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket + + 3.target1上使用步骤2创建的socket,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1 创建好TCP 连接,有ACCEPT + + 5.target停止调用recv + + 6.PC send 100 * 1460 data to 8266, + + 7.target重新调用recv' + sub module: TCP + summary: AP mode, recv buffer test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0212 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP -i + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -i + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SSC SSC1 soc -D -s + - ['R SSC1 RE SHUTDOWN:\d+,OK'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -L -s + - ['R SSC1 RE LISTEN:\d+,OK'] + - - SOC SOC2 CONNECT 0 + - ['R SSC1 A :ACCEPT:(\d+),\d+,.+,\d+'] + - - SSC SSC1 soc -I + - ['P SSC1 RE "SOCINFO:%%s,2,%%s,\d+,%%s,%%d"%%(,,,)', + 'P SSC1 RE "SOCINFO:%%s,2,.+,\d+,.+,\d+"%%()', 'P SSC1 RE "SOCINFO:%%s,82,.+,%%d"%%(,)', + 'P SSC1 RE "SOCINFO:%%s,2,%%s,%%d,%%s,\d+"%%(,,,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK,pc tcp server accept成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK + + 8.OK + + 9.PC OK, target1 +ACCEPT:3,2,,port + + 10.+SOCINFO:,,, + + +SOCINFO:,,, + + +SOCINFO:, + + +SOCINFO:,,, + + +SOCINF0ALL' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1,本地ip target_ip\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n4.target1上创建TCP socket2,本地ip target_ip\n5.target1上使用步骤4创建的socket2,去连接\ + \ PC的ip,test_tcp_port1,PC有ACCEPT\n6.target1 shutdown socket2 \n7.target1上创建TCP\ + \ socket3,本地端口random_port\n8.target1上使用步骤7创建的socket3,去监听\n9.PC CONNECT,\ + \ ,tcp 连接创建成功,创建socket4 \n10.target1 查询the socket information" + sub module: TCP + summary: AP mode, get active socket info test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use TCP SAP (socket/espconn API) in different state + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0401 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 sta -D + - ['P SSC1 C +QAP:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.断开与AP 连接 + + 6.8266往PC上发送5字节数据' + sub module: TCP + summary: do TCP send after WIFI disconnected + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0402 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 sta -D + - ['P SSC1 C +QAP:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.断开与AP 连接 + + 6.关闭建立的socket1连接' + sub module: TCP + summary: "close TCP socket after WIFI \ndisconnected" + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0403 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 op -S -o 2 + - ['P SSC1 C +MODE:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.修改8266的Mode为softAP mode\ + \ \n6.8266往PC上发送5字节数据" + sub module: TCP + summary: do TCP send after mode changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0404 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 op -S -o 2 + - ['P SSC1 C +MODE:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.修改8266的Mode为softAP mode\ + \ \n6.关闭建立的socket1连接" + sub module: TCP + summary: close TCP socket after mode changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0405 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - NIC DISABLED + - [R PC_COM C OK] + - - SSC SSC1 soc -S -s -l 1 + - [''] + - - DELAY 5400 + - ['P SSC1 RE CLOSED:\d+,0'] + comment: '' + execution time: 1.5 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.TCP连接断开' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.PC 网卡 disable + + 6.target1上使用socket1发送数据,等待 90 分钟' + sub module: TCP + summary: do TCP send after PC NIC disabled + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0406 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - NIC DISABLED + - [R PC_COM C OK] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.PC上网卡禁止掉 \n6.关闭建立的socket1连接" + sub module: TCP + summary: close TCP socket after PC NIC disabled + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0407 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.111.210 + - ['P SSC1 C +IP:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.111.210'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK + + 8.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.关闭8266的DHCP 1\n6.设置sta\ + \ ip \n7.查询sta ip 地址是否生效\n8.8266往PC上发送5字节数据" + sub module: TCP + summary: do TCP send after IP changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0408 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.111.210 + - ['P SSC1 C +IP:OK', 'P SSC1 RE CLOSED:\d+,0'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.111.210'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK + + 8.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上建立TCP 监听 test_tcp_port1\n2.target1上创建TCP socket1\n3.target1上使用步骤2创建的socket1,去连接\ + \ PC的ip,test_tcp_port1\n4.PC与target1创建好TCP 连接,有ACCEPT\n5.关闭8266的DHCP 1\n6.设置sta\ + \ ip \n7.查询sta ip 地址是否生效\n8.关闭建立的socket1连接" + sub module: TCP + summary: close TCP socket after IP changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0411 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + - - SSC SSC1 soc -S -s -l 5 + - ['P SSC1 RE SEND:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.ERROR + + 7.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.target1上创建TCP socket2 + + 6.8266往PC socket2上发送5字节数据 + + 7.8266往PC socket1上发送5字节数据' + sub module: TCP + summary: do TCP send after socket changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_TCP_0412 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -C -s -i -p + - ['R SSC1 RE CONNECT:\d+,OK'] + - - SOC SOC1 ACCEPT SOC2 + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t TCP + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上建立TCP 监听 test_tcp_port1 + + 2.target1上创建TCP socket1 + + 3.target1上使用步骤2创建的socket1,去连接 PC的ip,test_tcp_port1 + + 4.PC与target1创建好TCP 连接,有ACCEPT + + 5.target1上创建TCP socket2 + + 6.关闭socket1 连接 + + 7.关闭socket2连接' + sub module: TCP + summary: close TCP send after socket changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: TCP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -i 0.0.0.0 -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 C BIND:ERROR'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 RE BIND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上UDP传输,Bind socket2,本地ip 0.0.0.0 target_udp_port2 + + 3.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 4.target1上创建TCP socket3, target_udp_port1' + sub module: UDP + summary: STA mode, udp bind test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SOC SOC2 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 10 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 10] + - - SSC SSC1 soc -S -s -i -p -l 10 + - ['P SSC1 RE SEND:(\d+),OK', P SOC2 UL 10] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.PC上SOC2 UDP传输,bing + + 3.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 4.target1上使用步骤3创建的socket1,往pc_ip,test_tcp_port1上发送10字节数据 + + 5.target1上使用步骤3创建的socket1,往pc_ip2,test_tcp_port2上发送10字节数据' + sub module: UDP + summary: STA mode, sendto test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 1 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 1] + - - SSC SSC1 soc -S -s -i -p -l 1472 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 1472] + - - SSC SSC1 soc -S -s -i -p -l 1473 + - ['P SSC1 RE SEND:(\d+),OK', P SOC_COM NC SOC_RECVFROM] + - - SSC SSC1 soc -S -s -i -p -l 1472 -n 10 -j 20 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 14720] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK,没有到UDP包 + + 6.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1字节数据 + + 4.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1472字节数据 + + 5.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1473字节数据 + + 6.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1472*10字节数据' + sub module: UDP + summary: STA mode, sendto test with different length + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 SENDTO 1 + - [R SSC1 SL +1] + - - SOC SOC1 SENDTO 1472 + - ['R SSC1 RE "RECVFROM:%%s,1472,%%s,%%u"%%(,,)'] + - - SOC SOC1 SENDTO 1473 + - [P SSC1 NC +RECVFROM, P SOC_COM C OK] + - - SOC SOC2 BIND + - [R SOC_COM L OK] + - - SOC SOC2 SENDTO 1472 + - ['R SSC1 RE "RECVFROM:%%s,1472,%%s,%%u"%%(,,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK,没收到UDP包 + + 6.OK + + 7.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.PC往8266上发送1字节数据 + + 4.PC往8266上发送1472字节数据 + + 5.PC往8266上发送1473字节数据 + + 6.PC上SOC2 UDP传输,bing + + 7.PC往8266上发送1472字节数据' + sub module: UDP + summary: STA mode, recvfrom basic test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0105 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.关闭socket1' + sub module: UDP + summary: STA mode, close UDP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0106 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2.ok + + 3.ok + + 4.ok + + 5.ok' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上UDP传输,Bind socket2,本地ip target_udp_port2 + + 3.target1上UDP传输,Bind socket3,本地ip target_udp_port3 + + 4.target1上UDP传输,Bind socket4,本地ip target_udp_port4 + + 5.target1上UDP传输,Bind socket5,本地ip target_udp_port5' + sub module: UDP + summary: STA mode, create max udp socket test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0107 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -I + - ['P SSC1 RE "SOCINFO:%%s,1,.+,%%d"%%(,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上查询创建socket信息' + sub module: UDP + summary: STA mode, get active socket info test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0108 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -i 0.0.0.0 -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 C BIND:ERROR'] + - - SSC SSC1 soc -B -t TCP -p + - ['R SSC1 RE BIND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.ERROR + + 4.OK' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上UDP传输,Bind socket2,本地ip 0.0.0.0 target_udp_port2 + + 3.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 4.target1上创建TCP socket3, target_udp_port1' + sub module: UDP + summary: AP mode, udp bind test. use different ip, port + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0110 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 1 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 1] + - - SSC SSC1 soc -S -s -i -p -l 1472 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 1472] + - - SSC SSC1 soc -S -s -i -p -l 1473 + - ['P SSC1 RE SEND:(\d+),OK', P SOC_COM NC SOC_RECVFROM] + - - SSC SSC1 soc -S -s -i -p -l 1472 -n 10 + -j 20 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 14720] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK,没收到UDP包 + + 6.OK' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1字节数据 + + 4.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1472字节数据 + + 5.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1473字节数据 + + 6.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送1472*10字节数据' + sub module: UDP + summary: AP mode, sendto test with different length + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0112 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.关闭socket1' + sub module: UDP + summary: AP mode, close UDP sockets test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0113 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 RE BIND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.ok + + 2.ok + + 3.ok + + 4.ok + + 5.ok' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上UDP传输,Bind socket2,本地ip target_udp_port2 + + 3.target1上UDP传输,Bind socket3,本地ip target_udp_port3 + + 4.target1上UDP传输,Bind socket4,本地ip target_udp_port4 + + 5.target1上UDP传输,Bind socket5,本地ip target_udp_port5' + sub module: UDP + summary: AP mode, create max udp socket test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0114 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -I + - ['P SSC1 RE "SOCINFO:%%s,1,.+,%%d"%%(,)'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 2.target1上查询创建socket信息' + sub module: UDP + summary: AP mode, get active socket info test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: use UDP SAP (socket/espconn API) with different parameter + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p -w 0 + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.PC OK + + 5.PC OK + + 6.PC OK + + 7.PC OK + + 8.PC OK SOC_CLOSE=SOC1' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上关闭工作线程 + + 4.PC往8266上发送1472字节数据 + + 5.PC往8266上发送1472字节数据 + + 6.PC往8266上发送1472字节数据 + + 7.PC往8266上发送1472字节数据 + + 8.PC往8266上发送1472字节数据' + sub module: UDP + summary: STA mode, recv buffer test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: use UDP SAP (socket/espconn API) in different state + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0202 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + - - SOC SOC1 SENDTO 1472 + - [''] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.PC OK + + 5.PC OK + + 6.PC OK + + 7.PC OK + + 8.PC OK SOC_CLOSE=SOC1' + initial condition: APSTA2 + initial condition description (auto): testing ap on sta + ap mode, PC join AP (autogen + by APM2) + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上关闭工作线程 + + 4.PC往8266上发送1472字节数据 + + 5.PC往8266上发送1472字节数据 + + 6.PC往8266上发送1472字节数据 + + 7.PC往8266上发送1472字节数据 + + 8.PC往8266上发送1472字节数据' + sub module: UDP + summary: AP mode, recv buffer test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: use UDP SAP (socket/espconn API) in different state + version: v2 (2016-10-19) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0301 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -i -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 sta -D + - ['P SSC1 C +QAP:OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:\d+,ERROR'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据 + + 4.断开与AP 连接 + + 5.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据' + sub module: UDP + summary: do UDP send after WIFI disconnected + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0302 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 sta -D + - ['P SSC1 C +QAP:OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: '1.PC上SOC1 UDP传输,bing + + 2.target1上UDP传输,Bind socket1,本地ip target_udp_port1 + + 3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据 + + 4.断开与AP 连接 + + 5.关闭建立的socket1连接' + sub module: UDP + summary: "close UDP socket after WIFI \ndisconnected" + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0303 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 op -S -o 2 + - ['P SSC1 C +MODE:OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.ERROR' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.修改8266的Mode为softAP mode \n5.8266往PC上发送5字节数据" + sub module: UDP + summary: do UDP send after mode changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0304 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 op -S -o 2 + - ['P SSC1 C +MODE:OK'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.修改8266的Mode为softAP mode \n5.关闭建立的socket1连接" + sub module: UDP + summary: close UDP socket after mode changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0305 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - NIC DISABLED + - [R PC_COM C OK] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK + + 4.OK + + 5.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.PC上网卡禁止掉 \n5.关闭建立的socket1连接" + sub module: UDP + summary: close UDP socket after PC NIC disabled + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0306 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.111.210 + - ['P SSC1 C +IP:OK'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.111.210'] + - - SSC SSC1 soc -S -s -i -p -l 1 + - ['P SSC1 RE SEND:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.关闭8266的DHCP 1\n5.设置sta ip \n6.查询sta ip 地址是否生效\n7.8266往PC上发送5字节数据" + sub module: UDP + summary: do UDP send after IP changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^TCPIP_UDP_0307 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: 1/5 + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SOC SOC1 BIND + - [R SOC_COM L OK] + - - SSC SSC1 soc -B -t UDP -p + - ['R SSC1 A :BIND:(\d+),OK'] + - - SSC SSC1 soc -S -s -i -p -l 5 + - ['P SSC1 RE SEND:(\d+),OK', P SOC1 UL 5] + - - SSC SSC1 dhcp -E -o 1 + - ['R SSC1 C +DHCP:STA,OK'] + - - SSC SSC1 ip -S -o 1 -i 192.168.111.210 + - ['P SSC1 C +IP:OK'] + - - SSC SSC1 ip -Q -o 1 + - ['R SSC1 C +STAIP:192.168.111.210'] + - - SSC SSC1 soc -T -s + - ['R SSC1 RE CLOSE:\d+,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.OK + + 3.OK; PC TCP server accept 成功 + + 4.OK + + 5.OK + + 6.OK + + 7.OK' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: TCPIP + steps: "1.PC上SOC1 UDP传输,bing \n2.target1上UDP传输,Bind socket1,本地ip\ + \ target_udp_port1\n3.target1上使用步骤2创建的socket1,往pc_ip,test_tcp_port1上发送5字节数据\n\ + 4.关闭8266的DHCP 1\n5.设置sta ip \n6.查询sta ip 地址是否生效\n7.关闭建立的socket1连接" + sub module: UDP + summary: close UDP socket after IP changed + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: UDP handling abnormal event + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_ADDR_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 1 -m 44:55:66:77:88:99 + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 mac -S -o 2 -m 22:33:44:55:66:77 + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 mac -Q -o 3 + - ['R SSC1 C +STAMAC:44:55:66:77:88:99 C +APMAC:22:33:44:55:66:77'] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.ok + + 3.ok + + 4.ok + + 5.ok + + 6.ok' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: "1.target1 设置mode 为sta+softAP mode\n2.target1 设置sta mode 下的mac \n3.target1\ + \ 设置softAP mode 下的mac\n4.target1 查询softAP+sta 下的mac\n5.target1 设置sta mode 下的mac\ + \ 为target1_mac\n6.target1 设置softAP mode 下的mac 为target1_ap_mac" + sub module: MAC Address + summary: set mac, query mac + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: mac address function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_ADDR_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 mac -S -o 2 -m 44:55:66:77:88:99 + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - [''] + - - SSC SSC2 sta -S -b 44:55:66:77:88:99 + - ['R SSC2 RE \+SCAN:.+,44:55:66:77:88:99,'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -Q -o 1 + - ['R SSC2 A :\+STAMAC:(.+)\r\n'] + - - SSC SSC2 mac -S -o 1 -m 22:33:44:55:66:77 + - ['R SSC2 C +MAC:STA,OK'] + - - SSC SSC2 sta -C -s -p + - ['P SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 ap -L + - ['R SSC1 C +LSTA:22:33:44:55:66:77'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + comment: '' + execution time: 0.0 + expected result: '1.OK + + 2.ok + + 3.ok + + 4.ok + + 5.ok + + 6.ok + + 7.ok + + 8.ok + + 9.ok' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: "1.target1 设置sta mode下的mac 44:55:66:77:88:99\n2.target1下设置ssid 和pwd 加密方式\n\ + 3.target2 查询mac为44:55:66:77:88:99的ssid\n4.target1 设置sta mode下的mac target_ap_mac\n\ + 5.target2 查询sta mode 下的mac 为target2_mac_tmp\n6.target2 设置sta mode 下的mac 为22:33:44:55:66:77\n\ + 7.target2 jap target1\n8.target1 查询连接到的sta \n9.target2 设置sta mode 下的mac 为 target2_mac" + sub module: MAC Address + summary: set mac and do scan/JAP/SAP + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: mac address function test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -t 0 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -p -t 2 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -p -t 4 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 ap -S -s -p -t 1 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S + - ['R SSC2 RE "\+SCAN:%%s,.+,0,\d+"%%()'] + - - SSC SSC1 ap -S -s -p -t 5 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S + - ['R SSC2 RE "\+SCAN:%%s,.+,0,\d+"%%()'] + comment: '' + execution time: 0.0 + expected result: "1.target1 set AP,open, \n2.target 2 jap succeed\n3.target1 set\ + \ AP,wpa_psk \n4.target 2 jap succeed\n5.target1 set AP, wpa2_psk \n6.target 2\ + \ jap succeed\n7.target1 set AP,wap_wpa2_psk\n8.target 2 jap succeed\n9.target1\ + \ set AP,加密方式为t 1\n10.target 2 上查询到target_ssid\n11.target1 set AP,加密方式为t 5\n12.target\ + \ 2 上查询到target_ssid" + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: "1.target1下设置ssid 和pwd,加密方式 open\n2.target2 jap target1\n3.target1下设置ssid\ + \ 和pwd,加密方式 wpa_psk \n4.target2 jap target1\n5.target1下设置ssid 和pwd,加密方式 wpa2_psk\ + \ \n6.target 2 jap target1\n7.target1下设置ssid 和pwd,加密方式 wap_wpa2_psk\n8.target2\ + \ jap target1\n9.target1下设置ssid 和pwd,加密方式 wep \n10.target2上查询target_ssid\n11.target1下设置ssid\ + \ 和pwd,加密方式 t 5 错误的加密方式\n12.target2上查询 target_ssid" + sub module: WIFI Connect + summary: station SAP+JAP test, different encryption + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: SAP/JAP with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t -h + 0 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 P , R SSC2 C +SCANDONE] + - - SSC SSC1 ap -S -s -p -t -h + 1 + - ['R SSC1 C +SAP:OK'] + - - DELAY 3 + - [''] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 C +SCANDONE] + - - DELAY 3 + - [''] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 NP C +SCANDONE] + comment: '' + execution time: 0.0 + expected result: '1.target1 set AP,set ssid broad cast + + 2.target 2上scan target_ap_mac + + 3.target1 set AP,set ssid hidden, + + 4.target 2上不能scan target_ap_mac' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. target1下设置ssid 和pwd 加密方式,set ssid broad cast + + 2.target 2上scan target_ap_mac + + 3. target1下设置ssid 和pwd 加密方式,set ssid hidden, + + 4.target 2上scan target_ap_mac' + sub module: WIFI Connect + summary: station SAP+JAP test, ssid hidden + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: SAP/JAP with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t -m + 1 + - ['R SSC1 C +SAP:OK'] + - - WIFI DISCONN + - ['R PC_COM C +WIFIDISCONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - WIFI CONN + + - ['R PC_COM C +WIFICONN:ERROR'] + comment: '' + execution time: 0.0 + expected result: '1. target1 set AP,set max allowed sta as 1 + + 2. use PC disconnect, + + 3.target 2 jap succeed + + 4.PC WIFI can not CONN' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1.target1下设置ssid 和pwd 加密方式,set max allowed sta as 1 + + 2.use PC disconnect target1 + + 3.target 2 jap target1 + + 4.PC WIFI CONNECT target1' + sub module: WIFI Connect + summary: station SAP test, max allowed sta + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: SAP/JAP with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0201 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 sta -Q + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:OK'] + - - SSC SSC1 sta -Q + - ['R SSC1 C +JAP:DISCONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.target1 jion AP 成功 + + 2.查询JAP的状态 + + 3.target1 断开AP + + 4.查询target1 JAP 是DISCONN' + initial condition: STAAP1 + initial condition description (auto): testing sta on sta + ap mode, quit AP (autogen + by STAM1) + level: Integration + module: WIFI MAC + steps: '1.target1 jion AP 成功 + + 2.查询JAP的状态 + + 3.target1 断开AP + + 4.查询target1 JAP 是DISCONN' + sub module: WIFI Connect + summary: JAP query test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: query JAP status + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0301 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t -h + 0 -m 8 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,3,0,8,\d+"%%(,)'] + comment: '' + execution time: 0.0 + expected result: '1. target1 set AP + + 2.target 1上查询到跟设置AP时一致' + initial condition: APSTA1 + initial condition description (auto): testing ap on sta + ap mode (autogen by APM1) + level: Integration + module: WIFI MAC + steps: '1. target1 set AP + + 2.target 1上查询到跟设置AP时一致' + sub module: WIFI Connect + summary: AP config query test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: query AP config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0401 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -R -a 0 + - ['R SSC1 C +AUTORECONN:OK'] + - - SSC SSC1 sta -R -a 2 + - ['R SSC1 C +AUTORECONN:0'] + - - SSC SSC1 reboot + - [''] + - - DELAY 15 + - [''] + - - SSC SSC1 sta -Q + - ['R SSC1 C JAP:DISCONNECTED'] + - - SSC SSC1 sta -R -a 1 + - ['R SSC1 C +AUTORECONN:OK'] + - - SSC SSC1 sta -R -a 2 + - ['R SSC1 C +AUTORECONN:1'] + - - SSC SSC1 reboot + - ['R SSC1 C +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.设置autoreconn,关闭 + + 2.查询当前autoreconn状态是否关闭 + + 3.重启系统,等待15s + + 4.查询target1 未自动重连AP + + 5.设置autoreconn,开启 + + 6.查询当前autoreconn状态是否开启 + + 7.系统重启后target1 自动重连AP' + initial condition: STAAP2 + initial condition description (auto): testing sta on sta + ap mode, join AP, DHCP + on (autogen by STAM2) + level: Integration + module: WIFI MAC + steps: '1.设置autoreconn,关闭 + + 2.查询当前autoreconn状态是否关闭 + + 3.重启系统,等待15s + + 4.查询target1 未自动重连AP + + 5.设置autoreconn,开启 + + 6.查询当前autoreconn状态是否开启 + + 7.系统重启后target1 自动重连AP' + sub module: WIFI Connect + summary: auto reconnect test + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: power on auto reconnect test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0501 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 sta -R -r 1 + - ['R SSC2 C +RECONN:OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - DELAY 10 + - [''] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - DELAY 15 + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 sta -R -r 0 + - ['R SSC2 C +RECONN:OK'] + - - SSC SSC2 sta -R -r 2 + - ['R SSC2 C +RECONN:0'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - DELAY 10 + - [''] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - DELAY 15 + - [P PC_COM C +DELAYDONE, 'P SSC2 NC +JAP:CONNECTED'] + - - SSC SSC2 sta -R -r 1 + - ['R SSC2 C +RECONN:OK'] + comment: '' + execution time: 0.0 + expected result: '1.设置reconn,开启(此功能不需要重启系统) + + 2.target1 set AP + + 3.target2 JAP target1 成功 + + 4.target2 断开target1 连接 + + 5.等待10s,target2 自动重连target1 + + 6.成功 + + 7.查询reconn状态,关闭 + + 8.修改mode 成功 + + 9.等待15s,target2 不会自动重连target1' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: "1.设置reconn,开启(此功能不需要重启系统)\n2.target1下设置ssid 和pwd 加密方式\n3.target2 JAP target1\ + \ \n4.target1 修改mode 为sta mode\n5.等待10s,target1 修改mode 为softAP mode\n6.设置reconn,关闭\n\ + 7.查询reconn状态,关闭\n8.target1 修改mode 为sta mode\n9.等待15s,target1 修改mode 为softAP mode" + sub module: WIFI Connect + summary: reconnect policy test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: reconnect policy test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0502 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 sta -R -r 1 + - ['R SSC2 C +RECONN:OK'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - DELAY 5 + - ['R SSC2 C +JAP:DISCONNECTED'] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - DELAY 10 + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - DELAY 10 + - [P PC_COM C +DELAYDONE, 'P SSC2 NC +JAP:CONNECTED'] + comment: '' + execution time: 0.0 + expected result: '1.target1 set AP + + 2.target2 jap target 1 + + 3.设置reconn,开启(此功能不需要重启系统) + + 4.target2 断开target1 连接 + + 5.等待10s,target2 自动重连target1 + + 6.target2 断开target1 连接' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1.target1下设置ssid 和pwd 加密方式 + + 2.target2 jap target 1 + + 3.设置reconn,开启(此功能不需要重启系统) + + 4.target2 断开target1 连接 + + 5.等待10s,target2 自动重连target1 + + 6.target2 断开target1 连接' + sub module: WIFI Connect + summary: will not do reconnect after manually disconnected + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: abnormal/special use + test point 2: reconnect policy test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0601 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM C +WIFICONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 ap -L + - ['R SSC1 C +LSTA:', 'R SSC1 C +LSTA:', R SSC1 C +LSTADONE] + comment: '' + execution time: 0.0 + expected result: '1.target1 set AP + + 2.PC WIFI CONNECTED + + 3.target2 jap target 1 + + 4.查询到两个sta 连接到target1 上' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. target1下设置ssid 和pwd 加密方式 + + 2.PC WIFI CONNECTED target1 + + 3.target2 jap target 1 + + 4.查询到两个sta 连接到target1 上' + sub module: WIFI Connect + summary: list stations connected to soft ap test + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: list SoftAP connected station + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0801 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 0 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 ap -S -s -p -t 2 + - ['P SSC1 C +SAP:OK', 'P SSC2 C +JAP:AUTHCHANGED,2,0'] + - - SSC SSC1 ap -S -s -p -t 3 + - ['P SSC1 C +SAP:OK', 'P SSC2 C +JAP:AUTHCHANGED,3,2'] + - - SSC SSC1 ap -S -s -p -t 4 + - ['P SSC1 C +SAP:OK', 'P SSC2 C +JAP:AUTHCHANGED,4,3'] + - - SSC SSC1 ap -S -s -p -t 0 + - ['P SSC1 C +SAP:OK', 'P SSC2 C +JAP:AUTHCHANGED,0,4'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. succeed + + 3. auth change event old mode 0 new mode 2 + + 4. auth change event old mode 2 new mode 3 + + 5. auth change event old mode 3 new mode 4 + + 6. auth change event old mode 4 new mode 0' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. set target1 softap auth mode 0 + + 2. target2 connect to target1 + + 3. set target1 softap auth mode 2, wait sta connected + + 4. set target1 softap auth mode 3, wait sta connected + + 5. set target1 softap auth mode 4, wait sta connected + + 6. set target1 softap auth mode 0, wait sta connected' + sub module: WIFI Connect + summary: test auth change event + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi auth changed event test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0901 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: basic function + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - SSC SSC1 sta -D + - ['R SSC1 RE JAP:DISCONNECTED,\d+,8'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE JAP:DISCONNECTED,\d+,15'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE JAP:DISCONNECTED,\d+,201'] + comment: '' + execution time: 0.0 + expected result: '1. disconnect event reason REASON_ASSOC_LEAVE + + 2. disconnect event reason REASON_4WAY_HANDSHAKE_TIMEOUT + + 3. disconnect event reason REASON_NO_AP_FOUND' + initial condition: STAAP1 + initial condition description (auto): testing sta on sta + ap mode, quit AP (autogen + by STAM1) + level: Integration + module: WIFI MAC + steps: '1. sta connect to AP, and disconnect + + 2. connect to AP with wrong password + + 3. connect to AP not exist' + sub module: WIFI Connect + summary: test wifi disconnect reason REASON_ASSOC_LEAVE, REASON_4WAY_HANDSHAKE_TIMEOUT, + REASON_NO_AP_FOUND + test environment: SSC_T1_1 + test environment description (auto): 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi disconnect reason test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0902 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p + - ['R SSC1 C +JAP:CONNECTED'] + - - APC OFF + - [P PC_COM L OK, 'R SSC1 RE JAP:DISCONNECTED,\d+,200'] + - - APC ON + - [P PC_COM L OK] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. disconnect event REASON_BEACON_TIMEOUT' + initial condition: STAAP1 + initial condition description (auto): testing sta on sta + ap mode, quit AP (autogen + by STAM1) + level: Integration + module: WIFI MAC + steps: '1. connect to AP + + 2. AP power off' + sub module: WIFI Connect + summary: test wifi disconnect reason REASON_BEACON_TIMEOUT + test environment: SSC_T1_APC + test environment description (auto): "PC has 1 wired NIC connected to AP.\nPC has\ + \ 1 wired NIC connected to APC (static IP within the same subnet with APC). \n\ + APC control AP power supply. \nPC has 1 WiFi NIC. \n1 SSC target connect with\ + \ PC by UART." + test point 1: basic function + test point 2: wifi disconnect reason test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0903 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -C -s -p bacfd + - ['R SSC1 RE JAP:DISCONNECTED,\d+,2'] + comment: '' + execution time: 0.0 + expected result: 1. disconect event reason REASON_AUTH_EXPIRE + initial condition: STAAP1 + initial condition description (auto): testing sta on sta + ap mode, quit AP (autogen + by STAM1) + level: Integration + module: WIFI MAC + steps: 1. connect WEP ap with error password (valid wep password) + sub module: WIFI Connect + summary: test wifi disconnect reason REASON_AUTH_EXPIRE + test environment: SSC_T1_WEP + test environment description (auto): '1 SSC target connect with PC by UART. + + One WEP share key AP placed near SSC1.' + test point 1: basic function + test point 2: wifi disconnect reason test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_CONN_0904 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p -t 3 -m 1 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -C -s -p 1234567890 + - ['R SSC2 RE JAP:DISCONNECTED,\d+,204'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:OK'] + - - WIFI CONN + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - SSC SSC2 sta -C -s -p + - ['R SSC2 RE JAP:DISCONNECTED,\d+,5'] + - - WIFI DISCONN + - [P PC_COM C OK, 'R SSC2 C +JAP:CONNECTED'] + - - SSC SSC1 ap -S -s -p -t 3 -m 1 + - ['P SSC1 C +SAP:OK', 'P SSC2 RE JAP:DISCONNECTED,\d+,4'] + comment: '' + execution time: 0.0 + expected result: '1. succeed + + 2. disconnect event REASON_HANDSHAKE_TIMEOUT + + 3. succeed + + 4. succeed + + 5. disconnect event REASON_ASSOC_TOOMANY + + 6. succeed, target2 connect succeed + + 7. disconnect event REASON_ASSOC_EXPIRE' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1. config target1 softap max sta allowed 1 + + 2. target2 connect to target1 with wrong password + + 3. target2 disconnect + + 4. PC WIFI NIC connect to target1 + + 5. target2 connect to target1 with correct password + + 6. PC WIFI NIC disconnect + + 7. reconfig softap' + sub module: WIFI Connect + summary: test wifi disconnect reason REASON_ASSOC_TOOMANY, REASON_HANDSHAKE_TIMEOUT, + REASON_ASSOC_EXPIRE + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: wifi disconnect reason test + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_SCAN_0101 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 sta -S -s .,juhg123 + - ['R SSC2 NC +SCAN: C +SCANDONE'] + - - SSC SSC1 ap -S -s -p 123456789 -t 3 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -s + - ['R SSC2 C +SCAN:', R SSC2 P , 'R SSC2 NC +SCAN: C +SCANDONE'] + comment: '' + execution time: 0.0 + expected result: '1.target 2上不能scan .,juhg123 + + 2.target1 set AP + + 3.target2上查询到' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1.target 2 scan .,juhg123 + + 2.target1下设置ssid 和pwd 加密方式 + + 3.target2 scan ' + sub module: WIFI Scan + summary: scan with scan config ssid + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_SCAN_0102 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC2 sta -S -b ff:ff:ff:ff:ff:11 + - ['R SSC2 NC +SCAN: C +SCANDONE'] + - - SSC SSC2 sta -S -b + - ['R SSC2 RE "\+SCAN:.+,%%s"%%()', 'R SSC2 NC +SCAN: C +SCANDONE'] + comment: '' + execution time: 0.0 + expected result: '1.target2 上不能查询到此mac + + 2.target2上查询到' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1.target2 上查询此macff:ff:ff:ff:ff:11 + + 2.target2上查询' + sub module: WIFI Scan + summary: scan with scan config bssid + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_SCAN_0103 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 ap -S -s -p 123456789 -t 3 -n 6 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -n 5 + - [R SSC2 NP C +SCANDONE] + - - SSC SSC2 sta -S -n 6 + - ['R SSC2 C +SCAN:', R SSC2 P ] + comment: '' + execution time: 0.0 + expected result: '1.target1 QAP + + 2. target1 set AP,set channel 6 + + 3.target2 上scan不到 channel 5 + + 4.target2 上查询channel 6的' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1.target1 断开连接AP + + 2.target1下设置ssid 和pwd 加密方式,set channel 6 + + 3.target2 上scan channel 5 + + 4.target2 上查询channel 6的' + sub module: WIFI Scan + summary: scan with scan config channel + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) +- CI ready: 'Yes' + ID: ^WIFI_SCAN_0104 + SDK: '8266_NonOS + + 8266_RTOS + + ESP32_IDF' + Test App: SSC + allow fail: '' + auto test: 'Yes' + category: Function + cmd set: + - '' + - - SSC SSC1 ap -S -s -p 123456789 -t 3 -h 0 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 P C +SCANDONE] + - - SSC SSC2 sta -S -h 1 + - [R SSC2 P C +SCANDONE] + - - SSC SSC1 ap -S -s -p 123456789 -h 1 + - ['R SSC1 C +SAP:OK'] + - - SSC SSC2 sta -S -h 0 + - [R SSC2 NP C +SCANDONE] + - - SSC SSC2 sta -S -h 1 + - [R SSC2 P C +SCANDONE] + comment: '' + execution time: 0.0 + expected result: '1.target1 set AP,set ssid broad cast + + 2.target 2上scan + + 3.target 2上scan + + 4.target1 set AP,set ssid hidden, + + 5.target 2上不能查询到 + + 6.target 2上查询到' + initial condition: T2_2 + initial condition description (auto): target 1 as AP+STA, target 2 as AP+STA (autogen) + level: Integration + module: WIFI MAC + steps: '1.target1下设置ssid 和pwd 加密方式,set ssid broad cast + + 2.target 2上scan + + 3.target 2上scan + + 4.target1下设置ssid 和pwd 加密方式,set ssid hidden, + + 5.target 2上查询 + + 6.target 2上查询' + sub module: WIFI Scan + summary: scan with scan config show hidden + test environment: SSC_T2_1 + test environment description (auto): 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.' + test point 1: basic function + test point 2: scan with different config + version: v1 (2016-8-15) diff --git a/components/idf_test/integration_test/TestEnvAll.yml b/components/idf_test/integration_test/TestEnvAll.yml new file mode 100644 index 0000000000..b8a2a497c6 --- /dev/null +++ b/components/idf_test/integration_test/TestEnvAll.yml @@ -0,0 +1,288 @@ +test environment: +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_1, + test environment detail: 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_2, + test environment detail: 'PC has 1 WiFi NIC. + + 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_3, + test environment detail: 'Able to access WAN after connect to AP. + + 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_ADC, + test environment detail: 'PC has 1 wired NIC connected to AP. + + Analog input connect to AT1 TOUT. + + Multimeter connect to input, able to measure input voltage. + + 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC1, + test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\ + \ connected to APC (static IP within the same subnet with APC). \nAPC control\ + \ AP power supply. \nPC has 1 WiFi NIC. \n1 AT target connect with PC by UART\ + \ (AT and LOG port).", test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC2, + test environment detail: "Able to access WAN after connect to AP.\nPC has 1 wired\ + \ NIC connected to APC (static IP within the same subnet with APC). \nAPC control\ + \ AP power supply.\nPC has 1 WiFi NIC.\n1 AT target connect with PC by UART (AT\ + \ and LOG port).", test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_HighSpeedUART, + test environment detail: 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 AT target connect with PC by high speed UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_SmartConfigIOT, + test environment detail: '1 AT target connect with PC by UART (AT and LOG port). + + PC has 1 wired NIC connect to Common AP. + + Several AP are placed near AT target. + + Several smart phone installed test APK are placed near AT target.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_1, + test environment detail: 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_JAP, + test environment detail: "Several AP are placed near AT target.\nPC has 1 wired\ + \ NIC connected to APC (static IP within the same subnet with APC).\nAPC control\ + \ power supply for all APs. \n2 AT target connect with PC by UART (AT and LOG\ + \ port).", test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_Sleep, + test environment detail: 'AP support DTIM placed with AT target. + + 2 AT target connect with PC by UART (AT and LOG port). + + Multimeter connect with PC via GPIB. + + Series multimeter between GND and VCC of AT1. + + AT1''s light sleep wakeup pin and wakeup indication connect with AT2''s GPIO.', + test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_SmartConfig, + test environment detail: '2 AT target connect with PC by UART (AT and LOG port). + + PC has 1 WiFi NIC. + + One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: IR_T2_1, test environment detail: '[TBD] 本测试为非自动测试, 红外能够做到数据收发吻合即可通过', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: NVS_T1_1, + test environment detail: '1 NVS target connect with PC by UART. + + 1 SSC target connect with PC by UART. + + SSC2 GPIO connect to NVS1 power control pin.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', + basic param list: '', script path: EnvBase.py, tag: PWM_T1_1, test environment detail: "[TBD]\ + \ 1. PWM OS SDK 以及 Non-OS SDK的测试建议分开进行, 放在不同的文件夹, 防止文件命名混淆\n2. 分析CSV文件的Python脚本只能分析单个channel\ + \ \n3. 如果Init脚本打印\"Network Error\" 检查TCP Server是不是正常发送data", test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_1, + test environment detail: 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_2, + test environment detail: 'Able to access WAN after connect to AP. + + 1 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_8089, + test environment detail: 'PC has 1 wired NIC connected to AP. + + 1 8089 tablet able to run iperf test placed near SSC1. + + 1 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ADC, + test environment detail: 'PC has 1 wired NIC connected to AP. + + Analog input connect to SSC1 TOUT. + + Multimeter connect to input, able to measure input voltage. + + 1 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_APC, + test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\ + \ connected to APC (static IP within the same subnet with APC). \nAPC control\ + \ AP power supply. \nPC has 1 WiFi NIC. \n1 SSC target connect with PC by UART.", + test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Enterprise, + test environment detail: "AP use WPA2-Etherprise is placed near SSC1. \n1 SSC target\ + \ connect with PC by UART.", test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_IOT1, + test environment detail: 'PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART. + + AP todo IOT test are placed near SSC1.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T1_InitData, + test environment detail: '2 SSC target connect with PC by UART. + + SSC1 use 40M crystal oscillator. + + SSC2 use normal 26M crystal oscillator. + + SSC2 GPIO connect to SSC1 power control pin.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ShieldBox, + test environment detail: 'refer to figure. + + All APs and APC should be set to the same IP subnet. + + PC wired NIC should set static IP address within the same subnet with AP. + + Must use onboard wired NIC.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep1, + test environment detail: 'AP support DTIM placed with AT target. + + SSC target connect with Raspberry Pi by UART. + + Multimeter connect with Raspberry Pi via GPIB. + + Series multimeter between GND and VCC of SSC1. + + SSC1''s light sleep wakeup pin and wakeup indication connect with Raspberry Pi''s + GPIO. + + SSC1''s XPD connect with RSTB.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep2, + test environment detail: 'AP support DTIM placed with AT target. + + SSC target connect with Raspberry Pi by UART. + + Multimeter connect with Raspberry Pi via GPIB. + + Series multimeter between GND and VCC of SSC1. + + SSC1''s RSTB pin connect with Raspberry Pi''s GPIO.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_TempBox, + test environment detail: '1 SSC target connect with PC by UART. + + Put SSC target to temperature box.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', + basic param list: '', script path: EnvBase.py, tag: SSC_T1_Timer, test environment detail: '[TBD] + 通过串口工具调节Timer, 将GPIO_13端口连接到逻辑分析仪', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_VDD33, + test environment detail: '1 SSC target connect with PC by UART. + + Multimeter connect to VDD33, able to measure voltage.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_WEP, + test environment detail: '1 SSC target connect with PC by UART. + + One WEP share key AP placed near SSC1.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_1, + test environment detail: 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: SSC_T2_GPIO1, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266的 + GPIO_6相连', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: SSC_T2_GPIO2, test environment detail: '[TBD] 1. 2个ESP_8266通过UART连到PC, ESP_8266的 + GPIO_15通过面包板相连 + + 2. 可借助面包板, 将GPIO_15, 以及中断函数被打开的8266板的GPIO_2 相连', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: SSC_T2_GPIO3, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266之间需要测试的Target_GPIO相连', + test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_JAP, + test environment detail: 'PC has 1 wired NIC connected to APC. + + APC control the power supply of multiple APs. + + 2 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_PhyMode, + test environment detail: '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_ShieldBox, + test environment detail: '2 SSC target connect with PC by UART. + + Put them to Shield box.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_SmartConfig, + test environment detail: '2 SSC target connect with PC by UART. + + PC has 1 WiFi NIC. + + One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 3.0, script path: EnvBase.py, tag: SSC_T3_PhyMode, + test environment detail: '3 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). + + Put 4 APs near SSC targets.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_1, + test environment detail: 5 SSC target connect with PC by UART., test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_IOT1, + test environment detail: '5 SSC targets connect with PC by UART. + + some Android smart phone are placed near SSC targets.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T6_1, + test environment detail: 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 6 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: TempSensor_T1_1, + test environment detail: 'Tempeture sensor target connect with PC by UART. + + AP support DTIM placed with AT target. + + Multimeter connect with PC via GPIB. + + Series multimeter between GND and VCC of TempSensor1. + + PC has 1 wired NIC connected to switch. + + APC, AP also connect with swtich. + + All devices connected with switch use the same IP subnet. + + APC control AP power supply.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', + basic param list: '', script path: EnvBase.py, tag: UART_T1_1, test environment detail: '[TBD] + 将ESP_8266通过UART连到PC', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: UART_T1_2, test environment detail: '[TBD] ESP_8266通过UART_0通过USB, UART_1 TXD + 通过 TTLcable 连到PC', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_1, + test environment detail: Environment for running ESP32 unit tests, test script: EnvBase} +- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_1, + test environment detail: 'Web Server target connect with PC by UART. + + PC has 1 wired NIC connected to switch. + + APC, AP also connect with swtich. + + All devices connected with switch use same IP subnet. + + APC control AP power supply.', test script: EnvBase} +- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_2, + test environment detail: 'Web Server target connect with PC by UART. + + 4 PC with WiFi NIC placed near WebServer1.', test script: EnvBase} diff --git a/components/idf_test/unit_test/CIConfigs/UT_Function_SYS_01.yml b/components/idf_test/unit_test/CIConfigs/UT_Function_SYS_01.yml new file mode 100644 index 0000000000..c3561aa0c5 --- /dev/null +++ b/components/idf_test/unit_test/CIConfigs/UT_Function_SYS_01.yml @@ -0,0 +1,8 @@ +Config: {execute count: 1, execute order: in order} +DUT: [UT1] +Filter: +- Add: + ID: [SYS_OS_0102, SYS_MISC_0103, SYS_MISC_0102, SYS_MISC_0105, SYS_MISC_0104, + SYS_MISC_0107, SYS_MISC_0106, SYS_MISC_0109, SYS_MISC_0108, SYS_MISC_0112, SYS_MISC_0113, + SYS_MISC_0110, SYS_MISC_0111, SYS_MISC_0115, SYS_LIB_0103, SYS_LIB_0102, SYS_LIB_0101, + SYS_LIB_0106, SYS_LIB_0105, SYS_LIB_0104] diff --git a/components/idf_test/unit_test/InitialConditionAll.yml b/components/idf_test/unit_test/InitialConditionAll.yml new file mode 100644 index 0000000000..3821894552 --- /dev/null +++ b/components/idf_test/unit_test/InitialConditionAll.yml @@ -0,0 +1,2959 @@ +initial condition: +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + initial condition detail: AP mode, DHCP on, will autogen a TC with initial condition + APSTA1 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 31.0 + tag: APM1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 ap -L + - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + initial condition detail: AP mode, PC join AP, DHCP on, will autogen a TC with initial + condition APSTA2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 38.0 + tag: APM2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + initial condition detail: AP mode, will NOT autogen a TC with initial condition + APSTA1 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 31.0 + tag: APO1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 ap -L + - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + initial condition detail: AP mode, will NOT autogen a TC with initial condition + APSTA2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 38.0 + tag: APO2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 1 + - ['R SSC1 C BIN_ID,0'] + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + force restore cmd set: + - '' + - - SSC SSC1 upgrade -R -r 1 -s + - [R SSC1 NC ERROR C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SOC SOC1 ULISTEN + - [R SOC_COM L OK] + - - SOC SOC1 SETOPT REPLY BIN + - [R SOC_COM C OK] + - - SSC SSC1 upgrade -I -b 0 -f 0 + - ['P SSC1 C +UPGRADE:OK'] + - - SSC SSC1 upgrade -U -i -p -u + - ['P SSC1 C +UPGRADE:SUCCEED'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + initial condition detail: AP only mode, running BIN0 (located on flash id 0) + restore cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + restore post cmd set: + - '' + - - SSC SSC1 upgrade -D + - ['R SSC1 C +UPGRADE:OK'] + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 31.0 + tag: APOBIN0 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + initial condition detail: testing ap on sta + ap mode (autogen by APM1) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 59.0 + tag: APSTA1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC1 ap -Q + - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] + - - SSC SSC1 ap -L + - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + initial condition detail: testing ap on sta + ap mode, PC join AP (autogen by APM2) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC1 ap -S -s -p -t + - ['R SSC1 C +SAP:OK'] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 66.0 + tag: APSTA2 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - DELAY 5 + - [''] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + initial condition detail: StationSoftAP mode + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 24.0 + tag: ATAP1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:3 L OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - DELAY 5 + - [''] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + initial condition detail: StationSoftAP mode, PC join Target AP, multi link, use + dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 R *] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 31.0 + tag: ATAP3 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:3 L OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - DELAY 10 + - [''] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: StationSoftAP mode, PC join Target AP, single link, use + dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 45.0 + tag: ATAP4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: StationSoftAP mode, both PC join Target AP, single link, + use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATAP5 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: StationSoftAP mode, both PC join Target AP, multi link, + use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATAP6 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:2'] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + initial condition detail: SoftAP mode, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 59.0 + tag: ATAPO1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:2 L OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + initial condition detail: SoftAP mode, PC join Target AP, multi link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 R *] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 66.0 + tag: ATAPO3 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:2 L OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATC AT1 CWSAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + - - WIFI CONN + + - ['R PC_COM NC ERROR C +WIFICONN:OK'] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: SoftAP mode, PC join Target AP, single link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWLIF + - [R AT1 P ] + - - ATS AT1 AT+CWDHCP_DEF=0,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 73.0 + tag: ATAPO4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: SoftAP mode, both PC join Target AP, single link, use + dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATAPO5 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: SoftAP mode, both PC join Target AP, multi link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATAPO6 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + initial condition detail: StationSoftAP mode + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 87.0 + tag: ATAPSTA1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + initial condition detail: StationSoftAP mode, DHCP client on + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 87.0 + tag: ATAPSTA2 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + initial condition detail: StationSoftAP mode, connected to AP, multi link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 94.0 + tag: ATAPSTA3 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: StationSoftAP mode, connected to AP, single link, use + dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CWDHCP_DEF=2,1 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 101.0 + tag: ATAPSTA4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + initial condition detail: StationSoftAP mode, connected to AP, multi link, use static + ip + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 129.0 + tag: ATAPSTA5 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:3'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + initial condition detail: StationSoftAP mode, connected to AP, single link, use + static ip + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 136.0 + tag: ATAPSTA6 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT+RESTORE + - [R AT1 L OK, R AT1 C ready] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT+RESTORE + - [R AT1 L OK, R AT1 C ready] + initial condition detail: 'first time usage. Use restore function. ' + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+RESTORE + - [R AT1 L OK, R AT1 C ready] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 143.0 + tag: ATFTU + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT + - [R AT1 L OK] + - - ATS AT1 AT + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+RST + - [R AT1 L OK] + initial condition detail: none + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 3.0 + tag: ATNone + test script: InitCondBase +- check cmd set: + - '' + - - DELAY 0.1 + - [dummy] + force restore cmd set: + - '' + - - DELAY 0.1 + - [dummy] + initial condition detail: none 2 + restore cmd set: + - '' + - - DELAY 0.1 + - [dummy] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 108.0 + tag: ATNone2 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + initial condition detail: same as STA1, but will not autogen STA+AP STA test case + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 10.0 + tag: ATOSTA1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: same as STA4, but will not autogen STA+AP STA test case + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: ATOSTA4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:3 C OK'] + - - ATS AT2 AT+CWMODE_CUR? + - ['R AT2 C +CWMODE_CUR:1 C OK'] + - - ATS AT1 AT+CWJAP_CUR? + - [R AT1 NC OK L ERROR] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=1 + - [R AT2 L OK] + - - ATS AT1 AT+CWQAP + - [R AT1 L OK] + initial condition detail: same as OT2_1, but will not autogen STA+AP STA test case + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=1 + - [R AT2 L OK] + - - ATS AT1 AT+CWQAP + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 52.0 + tag: ATOT2_1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + initial condition detail: station mode, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 10.0 + tag: ATSTA1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + initial condition detail: station mode, DHCP client on, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 10.0 + tag: ATSTA2 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + initial condition detail: station mode, connected to AP, multi link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 38.0 + tag: ATSTA3 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CWDHCP_CUR? + - ['R AT1 C DHCP:3'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + initial condition detail: station mode, connected to AP, single link, use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATS AT1 AT+CWDHCP_DEF=1,1 + - [R AT1 R *] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: ATSTA4 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:1'] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + initial condition detail: station mode, connected to AP, multi link, use static + ip + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=1 + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 115.0 + tag: ATSTA5 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 L +CWMODE_CUR:1'] + - - ATS AT1 AT+CWJAP_CUR? + - ['R AT1 C +CWJAP_CUR:', R AT1 P ] + - - ATS AT1 AT+CIPMUX? + - ['R AT1 L +CIPMUX:0'] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + initial condition detail: station mode, connected to AP, single link, use static + ip + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=1 + - [R AT1 L OK] + - - ATC AT1 CWJAP_DEF + - [R AT1 L OK] + - - ATS AT1 AT+CIPSERVER=0 + - [R AT1 R *] + - - ATC AT1 CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMUX=0 + - [R AT1 L OK] + - - ATS AT1 AT+CIPCLOSE + - [R AT1 R *] + - - ATS AT1 AT+CIPMODE=0 + - [R AT1 R *] + - - ATC AT1 CIPSTA_DEF + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 122.0 + tag: ATSTA6 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:3 C OK'] + - - ATS AT2 AT+CWMODE_CUR? + - ['R AT2 C +CWMODE_CUR:1 C OK'] + - - ATS AT1 AT+CWJAP_CUR? + - [R AT1 NC OK L ERROR] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=1 + - [R AT2 L OK] + - - ATS AT1 AT+CWQAP + - [R AT1 L OK] + initial condition detail: Target 1 in StationSoftAP mode, Target 2 in station mode, + use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=3 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=1 + - [R AT2 L OK] + - - ATS AT1 AT+CWQAP + - [R AT1 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 52.0 + tag: ATT2_1 + test script: InitCondBase +- check cmd set: + - '' + - - ATS AT1 AT+CWMODE_CUR? + - ['R AT1 C +CWMODE_CUR:2 C OK'] + - - ATS AT2 AT+CWMODE_CUR? + - ['R AT2 C +CWMODE_CUR:3 C OK'] + - - ATS AT1 AT+CWJAP_CUR? + - [R AT1 NC OK L ERROR] + force restore cmd set: + - '' + - - ATS AT1 AT+RST + - [R AT1 C ready] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=3 + - [R AT2 L OK] + initial condition detail: Target 1 in SoftAP mode, Target 2 in StationSoftAP mode, + use dhcp + restore cmd set: + - '' + - - ATSO AT1 +++ + - [''] + - - ATS AT1 AT + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - ATS AT1 AT+CWMODE_DEF=2 + - [R AT1 L OK] + - - ATS AT2 AT+CWMODE_DEF=3 + - [R AT2 L OK] + restore post cmd set: + - '' + - - ATS AT1 AT+CWSTOPSMART + - [R AT1 R *] + - - ATS AT1 AT+SAVETRANSLINK=0 + - [R AT1 R *] + - - AT+SYSRAM + - ['R AT1 A :(\d+)'] + script path: InitCondBase.py + start: 80.0 + tag: ATT2_2 + test script: InitCondBase +- check cmd set: + - '' + - - ASSERT + - [dummy] + force restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['P SSC[1-] C !!!ready!!!'] + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] op -S -o 1 + - ['P SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] sta -D + - ['P SSC[1-] C +QAP:OK'] + initial condition detail: all mesh node disabled + restore cmd set: + - '' + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] op -S -o 1 + - ['P SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] sta -D + - ['P SSC[1-] C +QAP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 31.0 + tag: DISABLED + test script: InitCondBase +- check cmd set: + - '' + - - ASSERT + - [dummy] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + force restore cmd set: + - '' + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] mesh -I -g -a 4 -k -i + -p -h 5 + - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] + - - SSC SSC[1-] mesh -A -s -k + - ['P SSC[1-] C +MESHINIT:AP,OK'] + - - SSC SSC1 mesh -E -o 1 -t 2 + - ['P SSC1 C +MESH:ENABLED'] + - - SOC SOC1 MACCEPT GSOC1 + - [R SOC_COM L OK] + - - SSC SSC[2-] mesh -E -o 1 -t 2 + - ['P SSC[2-] C +MESH:ENABLED'] + - - DELAY 60 + - [''] + - - SSC SSC[1-] mesh -C + - ['P SSC[1-] C +MESH:CONNECTED'] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + - - SSC SSC[1-] mesh -O -t 1 -o 1 + - ['P SSC[1-] C +MESH:OK'] + initial condition detail: all mesh node enabled as ONLINE, mesh network established + restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['P SSC[1-] C !!!ready!!!'] + - - SOC SOC1 LISTEN + - [R SOC_COM L OK] + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] mesh -I -g -a 4 -k -i + -p -h 5 + - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] + - - SSC SSC[1-] mesh -A -s -k + - ['P SSC[1-] C +MESHINIT:AP,OK'] + - - SSC SSC1 mesh -E -o 1 -t 2 + - ['P SSC1 C +MESH:ENABLED'] + - - SOC SOC1 MACCEPT GSOC1 + - [R SOC_COM L OK] + - - SSC SSC[2-] mesh -E -o 1 -t 2 + - ['P SSC[2-] C +MESH:ENABLED'] + - - DELAY 60 + - [''] + - - SSC SSC[1-] mesh -C + - ['P SSC[1-] C +MESH:CONNECTED'] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + - - SSC SSC[1-] mesh -O -t 1 -o 1 + - ['P SSC[1-] C +MESH:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: ENABLED_1 + test script: InitCondBase +- check cmd set: + - '' + - - ASSERT + - [dummy] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + force restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['P SSC[1-] C !!!ready!!!'] + - - SSC SSC[1-] mesh -I -g -a 4 -k -i + -p -h 5 + - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] + - - SSC SSC1 mesh -A -s -k + - ['P SSC1 C +MESHINIT:AP,OK'] + - - SSC SSC1 mesh -E -o 1 -t 1 + - ['P SSC1 C +MESH:ENABLED'] + - - SSC SSC[2-] mesh -E -o 1 -t 2 + - [''] + - - DELAY 60 + - ['P SSC[2-] C +MESH:ENABLED'] + - - SSC SSC[1-] mesh -C + - ['P SSC[1-] C +MESH:CONNECTED'] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + initial condition detail: root as LOCAL, rest node as ONLINE, mesh network established + restore cmd set: + - '' + - - SSC SSC[1-] mesh -E -o 0 + - ['P SSC[1-] C +MESH:DISABLED'] + - - SSC SSC[1-] mesh -I -g -a 4 -k -i + -p -h 5 + - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] + - - SSC SSC1 mesh -A -s -k + - ['P SSC1 C +MESHINIT:AP,OK'] + - - SSC SSC1 mesh -E -o 1 -t 1 + - ['P SSC1 C +MESH:ENABLED'] + - - SSC SSC[2-] mesh -E -o 1 -t 2 + - [''] + - - DELAY 60 + - ['P SSC[2-] C +MESH:ENABLED'] + - - SSC SSC[1-] mesh -C + - ['P SSC[1-] C +MESH:CONNECTED'] + - - SSC SSC[1-] mesh -Q -t 4 + - ['R SSC[1-] T '] + - - MESHTREE + - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 24.0 + tag: ENABLED_2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + - - SSC SSC1 espnow -D + - ['R SSC1 C +ESPNOW:'] + force restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['R SSC[1-] C !!!ready!!!'] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -m -o 2 + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 espnow -D + - ['R SSC1 C +ESPNOW:'] + initial condition detail: one target in AP mode and espnow is de-initialized + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 mac -S -m -o 2 + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC1 espnow -D + - ['R SSC1 C +ESPNOW:'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: NOW1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC[1-] op -Q + - ['R SSC[1-] C +CURMODE:2'] + - - SSC SSC[1-] mac -Q -o 3 + - ['R SSC[1-] P ]_ap_mac> P ]_mac>'] + - - SSC SSC[1-] espnow -D + - ['R SSC[1-] C +ESPNOW:'] + - - SSC SSC[1-] espnow -I + - ['R SSC[1-] C +ESPNOW:OK'] + - - SSC SSC[1-] espnow -R -t Set -r 2 + - ['R SSC[1-] C +ESPNOW:OK'] + force restore cmd set: + - '' + - - SSC SSC[1-] reboot + - ['R SSC[1-] C !!!ready!!!'] + - - SSC SSC[1-] op -S -o 3 + - ['R SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 + - ['R SSC[1-] C +MAC:AP,OK'] + - - SSC SSC[1-] mac -S -m ]_mac> -o 1 + - ['R SSC[1-] C +MAC:STA,OK'] + - - SSC SSC[1-] op -S -o 2 + - ['R SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] espnow -D + - ['R SSC[1-] C +ESPNOW:'] + - - SSC SSC[1-] espnow -I + - ['R SSC[1-] C +ESPNOW:OK'] + - - SSC SSC[1-] espnow -R -t Set -r 2 + - ['R SSC[1-] C +ESPNOW:OK'] + initial condition detail: multiple () targets in AP mode, espnow is initialized + with self role slave + restore cmd set: + - '' + - - SSC SSC[1-] op -S -o 3 + - ['R SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 + - ['R SSC[1-] C +MAC:AP,OK'] + - - SSC SSC[1-] mac -S -m ]_mac> -o 1 + - ['R SSC[1-] C +MAC:STA,OK'] + - - SSC SSC[1-] op -S -o 2 + - ['R SSC[1-] C +MODE:OK'] + - - SSC SSC[1-] espnow -D + - ['R SSC[1-] C +ESPNOW:'] + - - SSC SSC[1-] espnow -I + - ['R SSC[1-] C +ESPNOW:OK'] + - - SSC SSC[1-] espnow -R -t Set -r 2 + - ['R SSC[1-] C +ESPNOW:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 24.0 + tag: NOW2 + test script: InitCondBase +- check cmd set: + - '' + - - DELAY 0.1 + - [dummy] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + initial condition detail: none + restore cmd set: + - '' + - - DELAY 0.1 + - [dummy] + restore post cmd set: + - '' + - - DELAY 0.1 + - [dummy] + script path: InitCondBase.py + start: 10.0 + tag: None + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 sp -D + - ['R SSC1 C +SP:OK'] + force restore cmd set: + - '' + - - SSC SSC1 sp -D + - ['R SSC1 C +SP:OK'] + initial condition detail: one target and simple is de-inited + restore cmd set: + - '' + - - SSC SSC1 sp -D + - ['R SSC1 C +SP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 31.0 + tag: PAIR1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC[1,2] op -Q + - ['R SSC[1,2] C +MODE:[2,1]'] + - - SSC SSC[1,2] mac -Q -o 3 + - ['R SSC[1,2] P P '] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + force restore cmd set: + - '' + - - SSC SSC[1,2] reboot + - ['R SSC[1,2] C !!!ready!!!'] + - - SSC SSC[1,2] op -S -o 3 + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] mac -S -m -o 2 + - ['R SSC[1,2] C +MAC:AP,OK'] + - - SSC SSC[1,2] mac -S -m -o 1 + - ['R SSC[1,2] C +MAC:STA,OK'] + - - SSC SSC[1,2] op -S -o [2,1] + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + initial condition detail: target1 in AP mode, target2 in STA mode, two targets de-init + and init simple pair + restore cmd set: + - '' + - - SSC SSC[1,2] op -S -o 3 + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] mac -S -m -o 2 + - ['R SSC[1,2] C +MAC:AP,OK'] + - - SSC SSC[1,2] mac -S -m -o 1 + - ['R SSC[1,2] C +MAC:STA,OK'] + - - SSC SSC[1,2] op -S -o [2,1] + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 38.0 + tag: PAIR2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC[1,2] op -Q + - ['R SSC[1,2] C +MODE:[3,3]'] + - - SSC SSC[1,2] mac -Q -o 3 + - ['R SSC[1,2] P P '] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + force restore cmd set: + - '' + - - SSC SSC[1,2] reboot + - ['R SSC[1,2] C !!!ready!!!'] + - - SSC SSC[1,2] op -S -o [3,3] + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] mac -S -m -o 2 + - ['R SSC[1,2] C +MAC:AP,OK'] + - - SSC SSC[1,2] mac -S -m -o 1 + - ['R SSC[1,2] C +MAC:STA,OK'] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + initial condition detail: target1 and target2 in STA+AP mode, two targets de-init + and init simple pair + restore cmd set: + - '' + - - SSC SSC[1,2] op -S -o [3,3] + - ['R SSC[1,2] C +MODE:OK'] + - - SSC SSC[1,2] mac -S -m -o 2 + - ['R SSC[1,2] C +MAC:AP,OK'] + - - SSC SSC[1,2] mac -S -m -o 1 + - ['R SSC[1,2] C +MAC:STA,OK'] + - - SSC SSC[1,2] sp -D + - ['R SSC[1,2] C +SP:OK'] + - - SSC SSC[1,2] sp -I + - ['R SSC[1,2] C +SP:OK'] + restore post cmd set: + - '' + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 45.0 + tag: PAIR3 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + initial condition detail: testing sta on sta + ap mode, quit AP (autogen by STAM1) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 45.0 + tag: STAAP1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC1 sta -Q + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: testing sta on sta + ap mode, join AP, DHCP on (autogen + by STAM2) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 52.0 + tag: STAAP2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 1 + - ['R SSC1 C BIN_ID,0'] + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + force restore cmd set: + - '' + - - SSC SSC1 upgrade -R -r 1 -s + - [R SSC1 NC ERROR C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SOC SOC1 ULISTEN + - [R SOC_COM L OK] + - - SOC SOC1 SETOPT REPLY BIN + - [R SOC_COM C OK] + - - SSC SSC1 upgrade -I -b 0 -f 0 + - ['P SSC1 C +UPGRADE:OK'] + - - SSC SSC1 upgrade -U -i -p -u + - ['P SSC1 C +UPGRADE:SUCCEED'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: APSTA mode, connected to AP, running BIN0 (located on + flash id 0) + restore cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 upgrade -D + - ['R SSC1 C +UPGRADE:OK'] + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 24.0 + tag: STAAPBIN0 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:1'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + initial condition detail: sta mode, quit AP, DHCP on, will autogen a TC with initial + condition STAAP1 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 17.0 + tag: STAM1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:1'] + - - SSC SSC1 sta -Q + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: sta mode, join AP, DHCP on, will autogen a TC with initial + condition STAAP2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 24.0 + tag: STAM2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 1 + - ['R SSC1 C BIN_ID,0'] + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + force restore cmd set: + - '' + - - SSC SSC1 upgrade -R -r 1 -s + - [R SSC1 NC ERROR C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SOC SOC1 ULISTEN + - [R SOC_COM L OK] + - - SOC SOC1 SETOPT REPLY BIN + - [R SOC_COM C OK] + - - SSC SSC1 upgrade -I -b 0 -f 0 + - ['P SSC1 C +UPGRADE:OK'] + - - SSC SSC1 upgrade -U -i -p -u + - ['P SSC1 C +UPGRADE:SUCCEED'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: STA mode, connected to AP, running BIN0 (located on flash + id 0) + restore cmd set: + - '' + - - SSC SSC1 upgrade -Q -t 2 -b 0 + - ['R SSC1 C BIN_INFO,0'] + - - SSC SSC1 upgrade -R -b 0 + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 upgrade -D + - ['R SSC1 C +UPGRADE:OK'] + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 17.0 + tag: STAMBIN0 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:1'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + initial condition detail: sta mode, quit AP, will NOT autogen a TC with initial + condition STAAP1 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 sta -D + - ['R SSC1 C +QAP:'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 17.0 + tag: STAO1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:1'] + - - SSC SSC1 sta -Q + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + - - SSC SSC1 dhcp -Q -o 1 + - ['R SSC1 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 1 + - [R SSC1 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + initial condition detail: sta mode, join AP, DHCP on, will NOT autogen a TC with + initial condition STAAP2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC1 dhcp -S -o 1 + - [R SSC1 C +DHCP] + - - SSC SSC1 mac -S -o 1 -m + - ['R SSC1 C +MAC:STA,OK'] + - - SSC SSC1 sta -C -s -p + - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 24.0 + tag: STAO2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC2 op -Q + - ['R SSC2 C +CURMODE:1'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC2 dhcp -Q -o 1 + - ['R SSC2 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + - - SSC SSC2 mac -Q -o 1 + - [R SSC2 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC2 reboot + - [R SSC2 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + initial condition detail: same as T2_1 but will NOT autogen a TC with initial condition + T2_2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 73.0 + tag: T2O_1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:2'] + - - SSC SSC2 op -Q + - ['R SSC2 C +CURMODE:1'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC2 dhcp -Q -o 1 + - ['R SSC2 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + - - SSC SSC2 mac -Q -o 1 + - [R SSC2 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC2 reboot + - [R SSC2 C !!!ready!!!] + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + initial condition detail: target 1 as SoftAP, target 2 as STA, will autogen a TC + with initial condition T2_2 + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 1 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [''] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 73.0 + tag: T2_1 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC1 op -Q + - ['R SSC1 C +CURMODE:3'] + - - SSC SSC2 op -Q + - ['R SSC2 C +CURMODE:3'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [R SSC2 C +CLOSEALL] + - - SSC SSC1 dhcp -Q -o 2 + - ['R SSC1 C +DHCP:AP,STARTED'] + - - SSC SSC2 dhcp -Q -o 1 + - ['R SSC2 C +DHCP:STA,STARTED'] + - - SSC SSC1 mac -Q -o 2 + - [R SSC1 P ] + - - SSC SSC2 mac -Q -o 1 + - [R SSC2 P ] + force restore cmd set: + - '' + - - SSC SSC1 reboot + - [R SSC1 C !!!ready!!!] + - - SSC SSC2 reboot + - [R SSC2 C !!!ready!!!] + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 3 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [R SSC2 C +CLOSEALL] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + initial condition detail: target 1 as AP+STA, target 2 as AP+STA (autogen) + restore cmd set: + - '' + - - SSC SSC1 op -S -o 3 + - ['R SSC1 C +MODE:OK'] + - - SSC SSC2 op -S -o 3 + - ['R SSC2 C +MODE:OK'] + - - SSC SSC2 sta -D + - ['R SSC2 C +QAP:'] + - - SSC SSC2 soc -T + - [R SSC2 C +CLOSEALL] + - - SSC SSC1 dhcp -S -o 2 + - [R SSC1 C +DHCP] + - - SSC SSC2 dhcp -S -o 1 + - [R SSC2 C +DHCP] + - - SSC SSC1 mac -S -o 2 -m + - ['R SSC1 C +MAC:AP,OK'] + - - SSC SSC2 mac -S -o 1 -m + - ['R SSC2 C +MAC:STA,OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 ram + - ['R SSC1 C +FREEHEAP:'] + script path: InitCondBase.py + start: 80.0 + tag: T2_2 + test script: InitCondBase +- check cmd set: + - '' + - - SSC SSC[1-3] op -Q + - ['R SSC[1-3] C +CURMODE:3'] + - - SSC SSC[1-3] phy -Q -o 3 + - ['R SSC[1-3] C STA,n,40 C AP,n,40'] + force restore cmd set: + - '' + - - SSC SSC[1-3] reboot + - ['R SSC[1-3] C !!!ready!!!'] + - - SSC SSC[1-3] op -S -o 3 + - ['R SSC[1-3] C +MODE:OK'] + - - SSC SSC[1-3] phy -S -o 3 -m n -b 40 + - ['R SSC[1-3] C +PHY:OK'] + initial condition detail: '1. target 1 and target 2 set to AP+STA mode, target 3 + set to STA mode + + 2. all interface of target 2,3 set to 11n ht40 + + 3. config softAP of target 1 and target 2' + restore cmd set: + - '' + - - SSC SSC[1-3] op -S -o 3 + - ['R SSC[1-3] C +MODE:OK'] + - - SSC SSC[1-3] phy -S -o 3 -m n -b 40 + - ['R SSC[1-3] C +PHY:OK'] + restore post cmd set: + - '' + - - SSC SSC1 soc -T + - [R SSC1 C +CLOSEALL] + - - SSC SSC1 sta -R -r 1 + - [R SSC1 C OK] + - - SSC SSC1 ram + - ['R SSC1 A :(\d+)'] + script path: InitCondBase.py + start: 87.0 + tag: T3_PHY1 + test script: InitCondBase +- check cmd set: + - '' + - - UT UT1 - + - [R UT1 C Tests C Failures C Ignored] + force restore cmd set: + - '' + - - FREBOOT UT1 + - [''] + - - UT UT1 - + - [R UT1 C Tests C Failures C Ignored] + initial condition detail: At UT menu page + restore cmd set: + - '' + - - FREBOOT UT1 + - [''] + - - UT UT1 - + - [R UT1 C Tests C Failures C Ignored] + restore post cmd set: + - '' + - - DELAY 0.1 + - [''] + script path: InitCondBase.py + tag: UTINIT1 + test script: InitCondBase diff --git a/components/idf_test/unit_test/TestCaseAll.yml b/components/idf_test/unit_test/TestCaseAll.yml new file mode 100644 index 0000000000..6f974e0bf5 --- /dev/null +++ b/components/idf_test/unit_test/TestCaseAll.yml @@ -0,0 +1,461 @@ +test cases: +- CI ready: 'Yes' + ID: SYS_LIB_0101 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "check if ROM is used for functions" + - [dummy] + comment: check if ROM is used for functions + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run lib test + sub module: Std Lib + summary: lib unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: lib + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_LIB_0102 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test time functions" + - [dummy] + comment: test time functions + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run lib test + sub module: Std Lib + summary: lib unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: lib + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_LIB_0103 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test sscanf function" + - [dummy] + comment: test sscanf function + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run lib test + sub module: Std Lib + summary: lib unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: lib + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_LIB_0104 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test sprintf function" + - [dummy] + comment: test sprintf function + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run lib test + sub module: Std Lib + summary: lib unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: lib + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_LIB_0105 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test atoX functions" + - [dummy] + comment: test atoX functions + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run lib test + sub module: Std Lib + summary: lib unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: lib + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_LIB_0106 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test ctype functions" + - [dummy] + comment: test ctype functions + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run lib test + sub module: Std Lib + summary: lib unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: lib + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0102 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "mbedtls MPI self-tests" + - [dummy] + comment: mbedtls MPI self-tests + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run bignum test + sub module: Misc + summary: bignum unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: bignum + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0103 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test AES thread safety" + - [dummy] + comment: test AES thread safety + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run hwcrypto test + sub module: Misc + summary: hwcrypto unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: hwcrypto + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0104 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test AES acceleration" + - [dummy] + comment: test AES acceleration + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run hwcrypto test + sub module: Misc + summary: hwcrypto unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: hwcrypto + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0105 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test SHA thread safety" + - [dummy] + comment: test SHA thread safety + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run hwcrypto test + sub module: Misc + summary: hwcrypto unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: hwcrypto + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0106 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "context switch saves FP registers" + - [dummy] + comment: context switch saves FP registers + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run fp test + sub module: Misc + summary: fp unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: fp + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0107 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test FP sqrt" + - [dummy] + comment: test FP sqrt + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run fp test + sub module: Misc + summary: fp unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: fp + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0108 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test FP div" + - [dummy] + comment: test FP div + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run fp test + sub module: Misc + summary: fp unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: fp + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0109 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test FP mul" + - [dummy] + comment: test FP mul + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run fp test + sub module: Misc + summary: fp unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: fp + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0110 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test FP add" + - [dummy] + comment: test FP add + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run fp test + sub module: Misc + summary: fp unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: fp + version: v1 (2016-10-26) +- CI ready: 'Yes' + ID: SYS_MISC_0111 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "Test JPEG decompression library" + - [dummy] + comment: Test JPEG decompression library + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run JPEG decompression test + sub module: Misc + summary: JPEG decompression library unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: tjpgd + version: v1 (2016-10-31) +- CI ready: 'Yes' + ID: SYS_MISC_0112 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "mbedtls AES self-tests" + - [dummy] + comment: mbedtls AES self-tests + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run mbedtls AES self-tests + sub module: Misc + summary: mbedtls AES unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: mbedtls AES + version: v1 (2016-10-31) +- CI ready: 'Yes' + ID: SYS_MISC_0113 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "mbedtls SHA self-tests" + - [dummy] + comment: mbedtls SHA self-tests + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run mbedtls SHA self-tests + sub module: Misc + summary: mbedtls SHA unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: mbedtls SHA + version: v1 (2016-10-31) +- CI ready: 'Yes' + ID: SYS_MISC_0115 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "test SHA acceleration" + - [dummy] + comment: test SHA acceleration + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run SHA acceleration test + sub module: Misc + summary: SHA acceleration unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: SHA acceleration + version: v1 (2016-10-31) +- CI ready: 'Yes' + ID: SYS_OS_0102 + SDK: ESP32_IDF + Test App: UT + auto test: 'Yes' + category: Function + cmd set: + - IDFUnitTest/UnitTest + - - test_case = "Freertos TLS delete cb" + - [dummy] + comment: Freertos TLS delete cb + execution time: 0 + expected result: 1. set succeed + initial condition: UTINIT1 + level: Unit + module: System + steps: 1. run Freertos TLS delete cb test + sub module: OS + summary: Freertos TLS delete cb unit test + test environment: UT_T1_1 + test point 1: basic function + test point 2: Freertos TLS delete cb + version: v1 (2016-10-31) diff --git a/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/UnitTest.py b/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/UnitTest.py new file mode 100644 index 0000000000..bfc8edeaa9 --- /dev/null +++ b/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/UnitTest.py @@ -0,0 +1,51 @@ +import re +import time + +from TCAction import PerformanceTCBase +from TCAction import TCActionBase +from NativeLog import NativeLog + +class UnitTest(PerformanceTCBase.PerformanceTCBase): + def __init__(self, name, test_env, cmd_set, timeout=30, log_path=TCActionBase.LOG_PATH): + PerformanceTCBase.PerformanceTCBase.__init__(self, name, test_env, cmd_set=cmd_set, + timeout=timeout, log_path=log_path) + + self.test_case = None + self.test_timeout = 20 + + # load param from excel + for i in range(1, len(cmd_set)): + if cmd_set[i][0] != "dummy": + cmd_string = "self." + cmd_set[i][0] + exec cmd_string + self.result_cntx = TCActionBase.ResultCheckContext(self, test_env, self.tc_name) + pass + + def send_commands(self): + self.flush_data("UT1") + + try: + # add case select by name mark " before case name + self.serial_write_line("UT1", "\"" + self.test_case) + data = "" + for _ in range(self.timeout): + time.sleep(1) #wait for test to run before reading result + data += self.serial_read_data("UT1") + if re.search('[^0] Tests 0 F', data): #check that number of tests run != 0 and number of tests failed == 0 + self.set_result("Succeed") + break + else: + self.set_result("Fail") + + except StandardError,e: + NativeLog.add_exception_log(e) + + def execute(self): + TCActionBase.TCActionBase.execute(self) + self.send_commands() + +def main(): + pass + +if __name__ == '__main__': + pass diff --git a/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py b/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py new file mode 100755 index 0000000000..876a5d4023 --- /dev/null +++ b/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py @@ -0,0 +1 @@ +__all__ = ["UnitTest"] diff --git a/components/idf_test/unit_test/TestEnvAll.yml b/components/idf_test/unit_test/TestEnvAll.yml new file mode 100644 index 0000000000..b8a2a497c6 --- /dev/null +++ b/components/idf_test/unit_test/TestEnvAll.yml @@ -0,0 +1,288 @@ +test environment: +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_1, + test environment detail: 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_2, + test environment detail: 'PC has 1 WiFi NIC. + + 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_3, + test environment detail: 'Able to access WAN after connect to AP. + + 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_ADC, + test environment detail: 'PC has 1 wired NIC connected to AP. + + Analog input connect to AT1 TOUT. + + Multimeter connect to input, able to measure input voltage. + + 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC1, + test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\ + \ connected to APC (static IP within the same subnet with APC). \nAPC control\ + \ AP power supply. \nPC has 1 WiFi NIC. \n1 AT target connect with PC by UART\ + \ (AT and LOG port).", test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC2, + test environment detail: "Able to access WAN after connect to AP.\nPC has 1 wired\ + \ NIC connected to APC (static IP within the same subnet with APC). \nAPC control\ + \ AP power supply.\nPC has 1 WiFi NIC.\n1 AT target connect with PC by UART (AT\ + \ and LOG port).", test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_HighSpeedUART, + test environment detail: 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 AT target connect with PC by high speed UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_SmartConfigIOT, + test environment detail: '1 AT target connect with PC by UART (AT and LOG port). + + PC has 1 wired NIC connect to Common AP. + + Several AP are placed near AT target. + + Several smart phone installed test APK are placed near AT target.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_1, + test environment detail: 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_JAP, + test environment detail: "Several AP are placed near AT target.\nPC has 1 wired\ + \ NIC connected to APC (static IP within the same subnet with APC).\nAPC control\ + \ power supply for all APs. \n2 AT target connect with PC by UART (AT and LOG\ + \ port).", test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_Sleep, + test environment detail: 'AP support DTIM placed with AT target. + + 2 AT target connect with PC by UART (AT and LOG port). + + Multimeter connect with PC via GPIB. + + Series multimeter between GND and VCC of AT1. + + AT1''s light sleep wakeup pin and wakeup indication connect with AT2''s GPIO.', + test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_SmartConfig, + test environment detail: '2 AT target connect with PC by UART (AT and LOG port). + + PC has 1 WiFi NIC. + + One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: IR_T2_1, test environment detail: '[TBD] 本测试为非自动测试, 红外能够做到数据收发吻合即可通过', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: NVS_T1_1, + test environment detail: '1 NVS target connect with PC by UART. + + 1 SSC target connect with PC by UART. + + SSC2 GPIO connect to NVS1 power control pin.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', + basic param list: '', script path: EnvBase.py, tag: PWM_T1_1, test environment detail: "[TBD]\ + \ 1. PWM OS SDK 以及 Non-OS SDK的测试建议分开进行, 放在不同的文件夹, 防止文件命名混淆\n2. 分析CSV文件的Python脚本只能分析单个channel\ + \ \n3. 如果Init脚本打印\"Network Error\" 检查TCP Server是不是正常发送data", test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_1, + test environment detail: 'PC has 2 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_2, + test environment detail: 'Able to access WAN after connect to AP. + + 1 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_8089, + test environment detail: 'PC has 1 wired NIC connected to AP. + + 1 8089 tablet able to run iperf test placed near SSC1. + + 1 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ADC, + test environment detail: 'PC has 1 wired NIC connected to AP. + + Analog input connect to SSC1 TOUT. + + Multimeter connect to input, able to measure input voltage. + + 1 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_APC, + test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\ + \ connected to APC (static IP within the same subnet with APC). \nAPC control\ + \ AP power supply. \nPC has 1 WiFi NIC. \n1 SSC target connect with PC by UART.", + test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Enterprise, + test environment detail: "AP use WPA2-Etherprise is placed near SSC1. \n1 SSC target\ + \ connect with PC by UART.", test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_IOT1, + test environment detail: 'PC has 1 WiFi NIC. + + 1 SSC target connect with PC by UART. + + AP todo IOT test are placed near SSC1.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T1_InitData, + test environment detail: '2 SSC target connect with PC by UART. + + SSC1 use 40M crystal oscillator. + + SSC2 use normal 26M crystal oscillator. + + SSC2 GPIO connect to SSC1 power control pin.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ShieldBox, + test environment detail: 'refer to figure. + + All APs and APC should be set to the same IP subnet. + + PC wired NIC should set static IP address within the same subnet with AP. + + Must use onboard wired NIC.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep1, + test environment detail: 'AP support DTIM placed with AT target. + + SSC target connect with Raspberry Pi by UART. + + Multimeter connect with Raspberry Pi via GPIB. + + Series multimeter between GND and VCC of SSC1. + + SSC1''s light sleep wakeup pin and wakeup indication connect with Raspberry Pi''s + GPIO. + + SSC1''s XPD connect with RSTB.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep2, + test environment detail: 'AP support DTIM placed with AT target. + + SSC target connect with Raspberry Pi by UART. + + Multimeter connect with Raspberry Pi via GPIB. + + Series multimeter between GND and VCC of SSC1. + + SSC1''s RSTB pin connect with Raspberry Pi''s GPIO.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_TempBox, + test environment detail: '1 SSC target connect with PC by UART. + + Put SSC target to temperature box.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', + basic param list: '', script path: EnvBase.py, tag: SSC_T1_Timer, test environment detail: '[TBD] + 通过串口工具调节Timer, 将GPIO_13端口连接到逻辑分析仪', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_VDD33, + test environment detail: '1 SSC target connect with PC by UART. + + Multimeter connect to VDD33, able to measure voltage.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_WEP, + test environment detail: '1 SSC target connect with PC by UART. + + One WEP share key AP placed near SSC1.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_1, + test environment detail: 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 2 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: SSC_T2_GPIO1, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266的 + GPIO_6相连', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: SSC_T2_GPIO2, test environment detail: '[TBD] 1. 2个ESP_8266通过UART连到PC, ESP_8266的 + GPIO_15通过面包板相连 + + 2. 可借助面包板, 将GPIO_15, 以及中断函数被打开的8266板的GPIO_2 相连', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: SSC_T2_GPIO3, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266之间需要测试的Target_GPIO相连', + test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_JAP, + test environment detail: 'PC has 1 wired NIC connected to APC. + + APC control the power supply of multiple APs. + + 2 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_PhyMode, + test environment detail: '2 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. + + Put 4 APs near SSC targets.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_ShieldBox, + test environment detail: '2 SSC target connect with PC by UART. + + Put them to Shield box.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_SmartConfig, + test environment detail: '2 SSC target connect with PC by UART. + + PC has 1 WiFi NIC. + + One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 3.0, script path: EnvBase.py, tag: SSC_T3_PhyMode, + test environment detail: '3 SSC target connect with PC by UART. + + PC has one WiFi NIC support capture wlan packet using libpcap. + + Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). + + Put 4 APs near SSC targets.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_1, + test environment detail: 5 SSC target connect with PC by UART., test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_IOT1, + test environment detail: '5 SSC targets connect with PC by UART. + + some Android smart phone are placed near SSC targets.', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T6_1, + test environment detail: 'PC has 1 wired NIC connected to AP. + + PC has 1 WiFi NIC. + + 6 SSC target connect with PC by UART.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: TempSensor_T1_1, + test environment detail: 'Tempeture sensor target connect with PC by UART. + + AP support DTIM placed with AT target. + + Multimeter connect with PC via GPIB. + + Series multimeter between GND and VCC of TempSensor1. + + PC has 1 wired NIC connected to switch. + + APC, AP also connect with swtich. + + All devices connected with switch use the same IP subnet. + + APC control AP power supply.', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', + basic param list: '', script path: EnvBase.py, tag: UART_T1_1, test environment detail: '[TBD] + 将ESP_8266通过UART连到PC', test script: EnvBase} +- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1 + + SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, + tag: UART_T1_2, test environment detail: '[TBD] ESP_8266通过UART_0通过USB, UART_1 TXD + 通过 TTLcable 连到PC', test script: EnvBase} +- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_1, + test environment detail: Environment for running ESP32 unit tests, test script: EnvBase} +- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_1, + test environment detail: 'Web Server target connect with PC by UART. + + PC has 1 wired NIC connected to switch. + + APC, AP also connect with swtich. + + All devices connected with switch use same IP subnet. + + APC control AP power supply.', test script: EnvBase} +- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_2, + test environment detail: 'Web Server target connect with PC by UART. + + 4 PC with WiFi NIC placed near WebServer1.', test script: EnvBase} diff --git a/components/json/component.mk b/components/json/component.mk index 311a902f99..2dd6ea8b87 100644 --- a/components/json/component.mk +++ b/components/json/component.mk @@ -1,13 +1,7 @@ # # Component Makefile # -# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, -# this will take the sources in this directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the SDK documents if you need to do this. -# COMPONENT_ADD_INCLUDEDIRS := include port/include COMPONENT_SRCDIRS := library port -include $(IDF_PATH)/make/component_common.mk diff --git a/components/log/README.rst b/components/log/README.rst new file mode 100644 index 0000000000..d378179c8f --- /dev/null +++ b/components/log/README.rst @@ -0,0 +1,61 @@ +Logging library +=============== + +Overview +-------- + +Log library has two ways of managing log verbosity: compile time, set via menuconfig; and runtime, using ``esp_log_set_level`` function. + +At compile time, filtering is done using ``CONFIG_LOG_DEFAULT_LEVEL`` macro, set via menuconfig. All logging statments for levels higher than ``CONFIG_LOG_DEFAULT_LEVEL`` will be removed by the preprocessor. + +At run time, all logs below ``CONFIG_LOG_DEFAULT_LEVEL`` are enabled by default. ``esp_log_set_level`` function may be used to set logging level per module. Modules are identified by their tags, which are human-readable ASCII zero-terminated strings. + +How to use this library +----------------------- + +In each C file which uses logging functionality, define TAG variable like this: + +.. code-block:: c + + static const char* TAG = "MyModule"; + +then use one of logging macros to produce output, e.g: + +.. code-block:: c + + ESP_LOGW(TAG, "Baud rate error %.1f%%. Requested: %d baud, actual: %d baud", error * 100, baud_req, baud_real); + +Several macros are available for different verbosity levels: + +* ``ESP_LOGE`` - error +* ``ESP_LOGW`` - warning +* ``ESP_LOGI`` - info +* ``ESP_LOGD`` - debug +* ``ESP_LOGV`` - verbose + +Additionally there is an _EARLY_ variant for each of these macros (e.g. ``ESP_EARLY_LOGE`` ).These variants can run in startup code, before heap allocator and syscalls have been initialized. When compiling bootloader, normal ``ESP_LOGx`` macros fall back to the same implementation as ``ESP_EARLY_LOGx`` macros. So the only place where ``ESP_EARLY_LOGx`` have to be used explicitly is the early startup code, such as heap allocator initialization code. + +(Note that such distinction would not have been necessary if we would have an ``ets_vprintf`` function in the ROM. Then it would be possible to switch implementation from _EARLY_ version to normal version on the fly. Unfortunately, ``ets_vprintf`` in ROM has been inlined by the compiler into ``ets_printf``, so it is not accessible outside.) + +To override default verbosity level at file or component scope, define ``LOG_LOCAL_LEVEL`` macro. At file scope, define it before including ``esp_log.h``, e.g.: + +.. code-block:: c + + #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE + #include "esp_log.h" + + +At component scope, define it in component makefile: + +.. code-block:: make + + CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG + +To configure logging output per module at runtime, add calls to ``esp_log_set_level`` function: + +.. code-block:: c + + esp_log_set_level("*", ESP_LOG_ERROR); // set all components to ERROR level + esp_log_set_level("wifi", ESP_LOG_WARN); // enable WARN logs from WiFi stack + esp_log_set_level("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client + diff --git a/components/log/component.mk b/components/log/component.mk index ef497a7ecb..c2c4c03a1a 100755 --- a/components/log/component.mk +++ b/components/log/component.mk @@ -1,3 +1,5 @@ -COMPONENT_ADD_INCLUDEDIRS := include +# +# Component Makefile +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) -include $(IDF_PATH)/make/component_common.mk diff --git a/components/log/include/esp_log.h b/components/log/include/esp_log.h index 8ca6e241d4..f4b9aa2885 100644 --- a/components/log/include/esp_log.h +++ b/components/log/include/esp_log.h @@ -19,81 +19,25 @@ #include #include "sdkconfig.h" +#ifdef BOOTLOADER_BUILD +#include +#endif + #ifdef __cplusplus extern "C" { #endif /** - * @brief Logging library - * - * Log library has two ways of managing log verbosity: compile time, set via - * menuconfig, and runtime, using esp_log_set_level function. - * - * At compile time, filtering is done using CONFIG_LOG_DEFAULT_LEVEL macro, set via - * menuconfig. All logging statments for levels higher than CONFIG_LOG_DEFAULT_LEVEL - * will be removed by the preprocessor. - * - * At run time, all logs below CONFIG_LOG_DEFAULT_LEVEL are enabled by default. - * esp_log_set_level function may be used to set logging level per module. - * Modules are identified by their tags, which are human-readable ASCII - * zero-terminated strings. - * - * How to use this library: - * - * In each C file which uses logging functionality, define TAG variable like this: - * - * static const char* TAG = "MyModule"; - * - * then use one of logging macros to produce output, e.g: - * - * ESP_LOGW(TAG, "Baud rate error %.1f%%. Requested: %d baud, actual: %d baud", error * 100, baud_req, baud_real); - * - * Several macros are available for different verbosity levels: - * - * ESP_LOGE — error - * ESP_LOGW — warning - * ESP_LOGI — info - * ESP_LOGD - debug - * ESP_LOGV - verbose - * - * Additionally there is an _EARLY_ variant for each of these macros (e.g. ESP_EARLY_LOGE). - * These variants can run in startup code, before heap allocator and syscalls - * have been initialized. - * When compiling bootloader, normal ESP_LOGx macros fall back to the same implementation - * as ESP_EARLY_LOGx macros. So the only place where ESP_EARLY_LOGx have to be used explicitly - * is the early startup code, such as heap allocator initialization code. - * - * (Note that such distinction would not have been necessary if we would have an - * ets_vprintf function in the ROM. Then it would be possible to switch implementation - * from _EARLY version to normal version on the fly. Unfortunately, ets_vprintf in ROM - * has been inlined by the compiler into ets_printf, so it is not accessible outside.) - * - * To override default verbosity level at file or component scope, define LOG_LOCAL_LEVEL macro. - * At file scope, define it before including esp_log.h, e.g.: - * - * #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE - * #include "esp_log.h" - * - * At component scope, define it in component makefile: - * - * CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG - * - * To configure logging output per module at runtime, add calls to esp_log_set_level function: - * - * esp_log_set_level("*", ESP_LOG_ERROR); // set all components to ERROR level - * esp_log_set_level("wifi", ESP_LOG_WARN); // enable WARN logs from WiFi stack - * esp_log_set_level("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client + * @brief Log level * */ - - typedef enum { - ESP_LOG_NONE, // No log output - ESP_LOG_ERROR, // Critical errors, software module can not recover on its own - ESP_LOG_WARN, // Error conditions from which recovery measures have been taken - ESP_LOG_INFO, // Information messages which describe normal flow of events - ESP_LOG_DEBUG, // Extra information which is not necessary for normal use (values, pointers, sizes, etc). - ESP_LOG_VERBOSE // Bigger chunks of debugging information, or frequent messages which can potentially flood the output. + ESP_LOG_NONE, /*!< No log output */ + ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */ + ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */ + ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */ + ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ + ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */ } esp_log_level_t; typedef int (*vprintf_like_t)(const char *, va_list); @@ -120,17 +64,6 @@ void esp_log_level_set(const char* tag, esp_log_level_t level); */ void esp_log_set_vprintf(vprintf_like_t func); -/** - * @brief Write message into the log - * - * This function is not intended to be used directly. Instead, use one of - * ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros. - * - * This function or these macros should not be used from an interrupt. - */ -void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4))); - - /** * @brief Function which returns timestamp to be used in log output * @@ -143,7 +76,17 @@ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, . * * @return timestamp, in milliseconds */ -uint32_t esp_log_timestamp(); +uint32_t esp_log_timestamp(void); + +/** + * @brief Write message into the log + * + * This function is not intended to be used directly. Instead, use one of + * ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros. + * + * This function or these macros should not be used from an interrupt. + */ +void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4))); #if CONFIG_LOG_COLORS diff --git a/components/log/log.c b/components/log/log.c index aae12a7735..9670b82dfd 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -284,7 +284,15 @@ static inline void heap_swap(int i, int j) } #endif //BOOTLOADER_BUILD -inline IRAM_ATTR uint32_t esp_log_early_timestamp() + +#ifndef BOOTLOADER_BUILD +#define ATTR IRAM_ATTR +#else +#define ATTR +#endif // BOOTLOADER_BUILD + + +uint32_t ATTR esp_log_early_timestamp() { return xthal_get_ccount() / (CPU_CLK_FREQ_ROM / 1000); } @@ -305,9 +313,6 @@ uint32_t IRAM_ATTR esp_log_timestamp() #else -uint32_t IRAM_ATTR esp_log_timestamp() -{ - return esp_log_early_timestamp(); -} +uint32_t esp_log_timestamp() __attribute__((alias("esp_log_early_timestamp"))); #endif //BOOTLOADER_BUILD diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 715d7dd467..801fa0b51c 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -7,7 +7,8 @@ config LWIP_MAX_SOCKETS help Sockets take up a certain amount of memory, and allowing fewer sockets to be open at the same time conserves memory. Specify - the maximum amount of sockets here. + the maximum amount of sockets here. The valid value is from 1 + to 16. config LWIP_THREAD_LOCAL_STORAGE_INDEX int "Index for thread-local-storage pointer for lwip" @@ -23,6 +24,15 @@ config LWIP_SO_REUSE Enabling this option allows binding to a port which remains in TIME_WAIT. +config LWIP_DHCP_MAX_NTP_SERVERS + int "Maximum number of NTP servers" + default 1 + range 1 16 + help + Set maxumum number of NTP servers used by LwIP SNTP module. + First argument of sntp_setserver/sntp_setservername functions + is limited to this value. + endmenu diff --git a/components/lwip/api/api_lib.c b/components/lwip/api/api_lib.c index c38c760811..ecebf4f813 100755 --- a/components/lwip/api/api_lib.c +++ b/components/lwip/api/api_lib.c @@ -55,11 +55,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - #define API_MSG_VAR_REF(name) API_VAR_REF(name) #define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) #define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name) @@ -178,8 +173,8 @@ netconn_delete(struct netconn *conn) return err; } -#if !LWIP_THREAD_SAFE - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("netconn_delete - free conn\n")); +#if !ESP_THREAD_SAFE + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("netconn_delete - free conn\n")); netconn_free(conn); #endif @@ -502,7 +497,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf) #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ #if (LWIP_UDP || LWIP_RAW) { -#if LWIP_THREAD_SAFE +#if ESP_THREAD_SAFE if (buf == NULL){ API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); return ERR_CLSD; @@ -710,17 +705,7 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, } dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); -#ifdef LWIP_ESP8266 - -#ifdef FOR_XIAOMI - if (dontblock && bytes_written) { -#else - if (dontblock && !bytes_written) { -#endif - -#else if (dontblock && !bytes_written) { -#endif /* This implies netconn_write() cannot be used for non-blocking send, since it has no way to return the number of bytes written. */ return ERR_VAL; diff --git a/components/lwip/api/api_msg.c b/components/lwip/api/api_msg.c index e8e967ef40..d504bfb877 100755 --- a/components/lwip/api/api_msg.c +++ b/components/lwip/api/api_msg.c @@ -55,10 +55,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - /* netconns are polled once per second (e.g. continue write on memory error) */ #define NETCONN_TCP_POLL_INTERVAL 2 @@ -314,8 +310,8 @@ poll_tcp(void *arg, struct tcp_pcb *pcb) if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { /* If the queued byte- or pbuf-count drops below the configured low-water limit, let select mark this pcb as writable again. */ - if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && - (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT(conn->pcb.tcp)) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT(conn->pcb.tcp))) { conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); } @@ -348,8 +344,8 @@ sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) /* If the queued byte- or pbuf-count drops below the configured low-water limit, let select mark this pcb as writable again. */ - if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && - (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT(conn->pcb.tcp) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT(conn->pcb.tcp)))) { conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); } @@ -1216,16 +1212,7 @@ lwip_netconn_do_connect(void *m) if (msg->conn->state == NETCONN_CONNECT) { msg->err = ERR_ALREADY; } else if (msg->conn->state != NETCONN_NONE) { - -#ifdef LWIP_ESP8266 - if( msg->conn->pcb.tcp->state == ESTABLISHED ) msg->err = ERR_ISCONN; - else - msg->err = ERR_ALREADY; -#else - msg->err = ERR_ISCONN; -#endif - } else { setup_tcp(msg->conn); msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), @@ -1540,8 +1527,8 @@ err_mem: and let poll_tcp check writable space to mark the pcb writable again */ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; - } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || - (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { + } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT(conn->pcb.tcp)) || + (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT(conn->pcb.tcp))) { /* The queued byte- or pbuf-count exceeds the configured low-water limit, let select mark this pcb as non-writable. */ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); @@ -1646,14 +1633,7 @@ lwip_netconn_do_write(void *m) if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) { LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); UNLOCK_TCPIP_CORE(); - -#ifdef LWIP_ESP8266 -//#if 0 - sys_arch_sem_wait( LWIP_API_MSG_SND_SEM(msg), 0); -#else - sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); -#endif - + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); LOCK_TCPIP_CORE(); LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE); } diff --git a/components/lwip/api/lwip_debug.c b/components/lwip/api/lwip_debug.c index 1e5fed40d3..d73a23e1a3 100644 --- a/components/lwip/api/lwip_debug.c +++ b/components/lwip/api/lwip_debug.c @@ -48,6 +48,9 @@ static void dbg_lwip_tcp_pcb_one_show(struct tcp_pcb* pcb) printf("rttest=%d rtseq=%d sa=%d sv=%d\n", pcb->rttest, pcb->rtseq, pcb->sa, pcb->sv); printf("rto=%d nrtx=%d\n", pcb->rto, pcb->nrtx); printf("dupacks=%d lastack=%d\n", pcb->dupacks, pcb->lastack); +#if ESP_PER_SOC_TCP_WND + printf("per_soc_window=%d per_soc_snd_buf=%d\n", pcb->per_soc_tcp_wnd, pcb->per_soc_tcp_snd_buf); +#endif printf("cwnd=%d ssthreash=%d\n", pcb->cwnd, pcb->ssthresh); printf("snd_next=%d snd_wl1=%d snd_wl2=%d\n", pcb->snd_nxt, pcb->snd_wl1, pcb->snd_wl2); printf("snd_lbb=%d snd_wnd=%d snd_wnd_max=%d\n", pcb->snd_lbb, pcb->snd_wnd, pcb->snd_wnd_max); diff --git a/components/lwip/api/netbuf.c b/components/lwip/api/netbuf.c index 6c6dc69ccd..9ab76a4638 100755 --- a/components/lwip/api/netbuf.c +++ b/components/lwip/api/netbuf.c @@ -45,11 +45,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /** * Create (allocate) and initialize a new netbuf. * The netbuf doesn't yet contain a packet buffer! diff --git a/components/lwip/api/netdb.c b/components/lwip/api/netdb.c index 8fd3f41861..65510f55e9 100755 --- a/components/lwip/api/netdb.c +++ b/components/lwip/api/netdb.c @@ -47,11 +47,6 @@ #include #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /** helper struct for gethostbyname_r to access the char* buffer */ struct gethostbyname_r_helper { ip_addr_t *addr_list[2]; diff --git a/components/lwip/api/sockets.c b/components/lwip/api/sockets.c index 350847b57c..1529382f50 100755 --- a/components/lwip/api/sockets.c +++ b/components/lwip/api/sockets.c @@ -61,11 +61,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /* If the netconn API is not required publicly, then we include the necessary files here to get the implementation */ #if !LWIP_NETCONN @@ -216,7 +211,7 @@ struct lwip_sock { /** last error that occurred on this socket (in fact, all our errnos fit into an u8_t) */ u8_t err; -#if LWIP_THREAD_SAFE +#if ESP_THREAD_SAFE /* lock is used to protect state/ref field, however this lock is not a perfect lock, e.g * taskA and taskB can access sock X, then taskA freed sock X, before taskB detect * this, taskC reuse sock X, then when taskB try to access sock X, problem may happen. @@ -239,7 +234,7 @@ struct lwip_sock { SELWAIT_T select_waiting; }; -#if LWIP_THREAD_SAFE +#if ESP_THREAD_SAFE #define LWIP_SOCK_OPEN 0 #define LWIP_SOCK_CLOSING 1 @@ -247,25 +242,25 @@ struct lwip_sock { #define LWIP_SOCK_LOCK(sock) \ do{\ - /*LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("l\n"));*/\ + /*LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("l\n"));*/\ sys_mutex_lock(&sock->lock);\ - /*LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("l ok\n"));*/\ + /*LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("l ok\n"));*/\ }while(0) #define LWIP_SOCK_UNLOCK(sock) \ do{\ sys_mutex_unlock(&sock->lock);\ - /*LWIP_DEBUGF(THREAD_SAFE_DEBUG1, ("unl\n"));*/\ + /*LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG1, ("unl\n"));*/\ }while(0) #define LWIP_FREE_SOCK(sock) \ do{\ if(sock->conn && NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP){\ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("LWIP_FREE_SOCK:free tcp sock\n"));\ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("LWIP_FREE_SOCK:free tcp sock\n"));\ free_socket(sock, 1);\ } else {\ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("LWIP_FREE_SOCK:free non-tcp sock\n"));\ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("LWIP_FREE_SOCK:free non-tcp sock\n"));\ free_socket(sock, 0);\ }\ }while(0) @@ -273,7 +268,7 @@ do{\ #define LWIP_SET_CLOSE_FLAG() \ do{\ LWIP_SOCK_LOCK(__sock);\ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("mark sock closing\n"));\ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mark sock closing\n"));\ __sock->state = LWIP_SOCK_CLOSING;\ LWIP_SOCK_UNLOCK(__sock);\ }while(0) @@ -291,7 +286,7 @@ do{\ LWIP_SOCK_LOCK(__sock);\ __sock->ref ++;\ if (__sock->state != LWIP_SOCK_OPEN) {\ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("LWIP_API_LOCK:soc is %d, return\n", __sock->state));\ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("LWIP_API_LOCK:soc is %d, return\n", __sock->state));\ __sock->ref --;\ LWIP_SOCK_UNLOCK(__sock);\ return -1;\ @@ -306,12 +301,12 @@ do{\ __sock->ref --;\ if (__sock->state == LWIP_SOCK_CLOSING) {\ if (__sock->ref == 0){\ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("LWIP_API_UNLOCK:ref 0, free __sock\n"));\ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("LWIP_API_UNLOCK:ref 0, free __sock\n"));\ LWIP_FREE_SOCK(__sock);\ LWIP_SOCK_UNLOCK(__sock);\ return __ret;\ }\ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("LWIP_API_UNLOCK: soc state is closing, return\n"));\ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("LWIP_API_UNLOCK: soc state is closing, return\n"));\ LWIP_SOCK_UNLOCK(__sock);\ return __ret;\ }\ @@ -387,36 +382,9 @@ static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, static void lwip_socket_drop_registered_memberships(int s); #endif /* LWIP_IGMP */ -#ifdef LWIP_ESP8266 - -/* Since esp_wifi_tx_is_stop/system_get_free_heap_size are not an public wifi API, so extern them here*/ -extern size_t system_get_free_heap_size(void); -extern bool esp_wifi_tx_is_stop(void); - -/* Please be notified that this flow control is just a workaround for fixing wifi Q full issue. - * Under UDP/TCP pressure test, we found that the sockets may cause wifi tx queue full if the socket - * sending speed is faster than the wifi sending speed, it will finally cause the packet to be dropped - * in wifi layer, it's not acceptable in some application. That's why we introdue the tx flow control here. - * However, current solution is just a workaround, we need to consider the return value of wifi tx interface, - * and feedback the return value to lwip and let lwip do the flow control itself. - */ -static inline void esp32_tx_flow_ctrl(void) -{ - uint8_t _wait_delay = 0; - - while ((system_get_free_heap_size() < HEAP_HIGHWAT) || esp_wifi_tx_is_stop()){ - vTaskDelay(_wait_delay/portTICK_RATE_MS); - if (_wait_delay < 64) _wait_delay *= 2; - } -} - -#else -#define esp32_tx_flow_ctrl() -#endif - /** The global array of available sockets */ static struct lwip_sock sockets[NUM_SOCKETS]; -#if LWIP_THREAD_SAFE +#if ESP_THREAD_SAFE static bool sockets_init_flag = false; #endif /** The global list of tasks waiting for select */ @@ -427,13 +395,7 @@ static volatile int select_cb_ctr; /** Table to quickly map an lwIP error (err_t) to a socket error * by using -err as an index */ -#ifdef LWIP_ESP8266 -//TO_DO -//static const int err_to_errno_table[] ICACHE_RODATA_ATTR STORE_ATTR = { static const int err_to_errno_table[] = { -#else -static const int err_to_errno_table[] = { -#endif 0, /* ERR_OK 0 No error, everything OK. */ ENOMEM, /* ERR_MEM -1 Out of memory error. */ ENOBUFS, /* ERR_BUF -2 Buffer error. */ @@ -444,7 +406,7 @@ static const int err_to_errno_table[] = { EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ EADDRINUSE, /* ERR_USE -8 Address in use. */ -#ifdef LWIP_ESP8266 +#if ESP_LWIP EALREADY, /* ERR_ALREADY -9 Already connected. */ EISCONN, /* ERR_ISCONN -10 Conn already established */ ECONNABORTED, /* ERR_ABRT -11 Connection aborted. */ @@ -585,7 +547,7 @@ alloc_socket(struct netconn *newconn, int accepted) int i; SYS_ARCH_DECL_PROTECT(lev); -#if LWIP_THREAD_SAFE +#if ESP_THREAD_SAFE bool found = false; int oldest = -1; @@ -641,16 +603,16 @@ alloc_socket(struct netconn *newconn, int accepted) if (!sockets[oldest].lock){ /* one time init and never free */ if (sys_mutex_new(&sockets[oldest].lock) != ERR_OK){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("new sock lock fail\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("new sock lock fail\n")); return -1; } } - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("alloc_socket: alloc %d ok\n", oldest)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("alloc_socket: alloc %d ok\n", oldest)); return oldest + LWIP_SOCKET_OFFSET; } - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("alloc_socket: failed\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("alloc_socket: failed\n")); #else @@ -695,12 +657,12 @@ free_socket(struct lwip_sock *sock, int is_tcp) void *lastdata; SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("free_sockset:free socket s=%p is_tcp=%d\n", sock, is_tcp)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("free_sockset:free socket s=%p is_tcp=%d\n", sock, is_tcp)); lastdata = sock->lastdata; sock->lastdata = NULL; sock->lastoffset = 0; sock->err = 0; -#if LWIP_THREAD_SAFE +#if ESP_THREAD_SAFE if (sock->conn){ netconn_free(sock->conn); } @@ -718,10 +680,10 @@ free_socket(struct lwip_sock *sock, int is_tcp) if (lastdata != NULL) { if (is_tcp) { - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("free_sockset:free lastdata pbuf=%p\n", lastdata)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("free_sockset:free lastdata pbuf=%p\n", lastdata)); pbuf_free((struct pbuf *)lastdata); } else { - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("free_sockset:free lastdata, netbuf=%p\n", lastdata)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("free_sockset:free lastdata, netbuf=%p\n", lastdata)); netbuf_delete((struct netbuf *)lastdata); } } @@ -874,19 +836,19 @@ lwip_close(int s) int is_tcp = 0; err_t err; - LWIP_DEBUGF(SOCKETS_DEBUG|THREAD_SAFE_DEBUG, ("lwip_close: (%d)\n", s)); + LWIP_DEBUGF(SOCKETS_DEBUG|ESP_THREAD_SAFE_DEBUG, ("lwip_close: (%d)\n", s)); sock = get_socket(s); if (!sock) { - LWIP_DEBUGF(SOCKETS_DEBUG|THREAD_SAFE_DEBUG, ("lwip_close: sock is null, return -1\n")); + LWIP_DEBUGF(SOCKETS_DEBUG|ESP_THREAD_SAFE_DEBUG, ("lwip_close: sock is null, return -1\n")); return -1; } if (sock->conn != NULL) { is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; - LWIP_DEBUGF(SOCKETS_DEBUG|THREAD_SAFE_DEBUG, ("lwip_close: is_tcp=%d\n", is_tcp)); + LWIP_DEBUGF(SOCKETS_DEBUG|ESP_THREAD_SAFE_DEBUG, ("lwip_close: is_tcp=%d\n", is_tcp)); } else { - LWIP_DEBUGF(SOCKETS_DEBUG|THREAD_SAFE_DEBUG, ("conn is null\n")); + LWIP_DEBUGF(SOCKETS_DEBUG|ESP_THREAD_SAFE_DEBUG, ("conn is null\n")); LWIP_ASSERT("lwip_close: sock->lastdata == NULL", sock->lastdata == NULL); } @@ -897,12 +859,12 @@ lwip_close(int s) err = netconn_delete(sock->conn); if (err != ERR_OK) { - LWIP_DEBUGF(SOCKETS_DEBUG|THREAD_SAFE_DEBUG, ("netconn_delete fail, ret=%d\n", err)); + LWIP_DEBUGF(SOCKETS_DEBUG|ESP_THREAD_SAFE_DEBUG, ("netconn_delete fail, ret=%d\n", err)); sock_set_errno(sock, err_to_errno(err)); return -1; } -#if !LWIP_THREAD_SAFE +#if !ESP_THREAD_SAFE free_socket(sock, is_tcp); #endif @@ -1132,22 +1094,13 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, ip_addr_debug_print(SOCKETS_DEBUG, fromaddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); -#ifdef LWIP_ESP8266 if (from && fromlen) -#else - -#if SOCKETS_DEBUG - if (from && fromlen) -#endif /* SOCKETS_DEBUG */ - -#endif { if (*fromlen > saddr.sa.sa_len) { *fromlen = saddr.sa.sa_len; } MEMCPY(from, &saddr, *fromlen); - -#ifdef LWIP_ESP8266 +#if ESP_LWIP } else { /*fix the code for setting the UDP PROTO's remote infomation by liuh at 2014.8.27*/ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_UDP){ @@ -1230,8 +1183,6 @@ lwip_send(int s, const void *data, size_t size, int flags) #endif /* (LWIP_UDP || LWIP_RAW) */ } - esp32_tx_flow_ctrl(); - write_flags = NETCONN_COPY | ((flags & MSG_MORE) ? NETCONN_MORE : 0) | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); @@ -1413,8 +1364,6 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #endif /* LWIP_TCP */ } - esp32_tx_flow_ctrl(); - if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); @@ -1439,7 +1388,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); } else { -#ifdef LWIP_ESP8266 +#if ESP_LWIP /*fix the code for getting the UDP proto's remote information by liuh at 2014.8.27*/ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_UDP){ if(NETCONNTYPE_ISIPV6(netconn_type(sock->conn))) { @@ -1455,7 +1404,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #endif remote_port = 0; ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); -#ifdef LWIP_ESP8266 +#if ESP_LWIP } #endif @@ -1988,7 +1937,7 @@ again: int lwip_shutdown(int s, int how) { -#ifndef LWIP_ESP8266 +#if ! ESP_LWIP struct lwip_sock *sock; err_t err; @@ -2395,6 +2344,16 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt s, *(int *)optval)); break; #endif /* LWIP_TCP_KEEPALIVE */ + +#if ESP_PER_SOC_TCP_WND + case TCP_WINDOW: + *(int*)optval = (int)sock->conn->pcb.tcp->per_soc_tcp_wnd; + break; + case TCP_SNDBUF: + *(int*)optval = (int)sock->conn->pcb.tcp->per_soc_tcp_snd_buf; + break; +#endif + default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); @@ -2792,6 +2751,16 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_ s, sock->conn->pcb.tcp->keep_cnt)); break; #endif /* LWIP_TCP_KEEPALIVE */ + +#if ESP_PER_SOC_TCP_WND + case TCP_WINDOW: + sock->conn->pcb.tcp->per_soc_tcp_wnd = ((u32_t)(*(const int*)optval)) * TCP_MSS; + break; + case TCP_SNDBUF: + sock->conn->pcb.tcp->per_soc_tcp_snd_buf = ((u32_t)(*(const int*)optval)) * TCP_MSS; + break; +#endif + default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); @@ -3108,7 +3077,7 @@ static void lwip_socket_drop_registered_memberships(int s) } #endif /* LWIP_IGMP */ -#if LWIP_THREAD_SAFE +#if ESP_THREAD_SAFE int lwip_sendto_r(int s, const void *data, size_t size, int flags, diff --git a/components/lwip/api/tcpip.c b/components/lwip/api/tcpip.c index 9df3c38a1d..0ad60721e4 100755 --- a/components/lwip/api/tcpip.c +++ b/components/lwip/api/tcpip.c @@ -50,18 +50,13 @@ #include "lwip/pbuf.h" #include "netif/etharp.h" -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - #define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) #define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name) #define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) /* global variables */ -#ifdef PERF +#if ESP_PERF uint32_t g_rx_post_mbox_fail_cnt = 0; #endif static tcpip_init_done_fn tcpip_init_done; @@ -144,13 +139,11 @@ tcpip_thread(void *arg) case TCPIP_MSG_INPKT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); -#ifdef LWIP_ESP8266 -//#if 0 +#if ESP_LWIP if(msg->msg.inp.p != NULL && msg->msg.inp.netif != NULL) { #endif msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif); -#ifdef LWIP_ESP8266 -//#if 0 +#if ESP_LWIP } #endif @@ -230,7 +223,7 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) msg->msg.inp.netif = inp; msg->msg.inp.input_fn = input_fn; if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { -#ifdef PERF +#if ESP_PERF g_rx_post_mbox_fail_cnt ++; #endif memp_free(MEMP_TCPIP_MSG_INPKT, msg); @@ -503,7 +496,7 @@ tcpip_init(tcpip_init_done_fn initfunc, void *arg) #endif /* LWIP_TCPIP_CORE_LOCKING */ -#ifdef LWIP_ESP8266 +#if ESP_LWIP sys_thread_t xLwipTaskHandle = sys_thread_new(TCPIP_THREAD_NAME , tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); @@ -548,8 +541,7 @@ pbuf_free_callback(struct pbuf *p) * @return ERR_OK if callback could be enqueued, an err_t if not */ -#ifdef LWIP_ESP8266 -//#if 0 +#if ESP_LWIP static void mem_free_local(void *arg) { mem_free(arg); diff --git a/components/lwip/apps/dhcpserver.c b/components/lwip/apps/dhcpserver.c index 4cdef4123d..22443e8cde 100644 --- a/components/lwip/apps/dhcpserver.c +++ b/components/lwip/apps/dhcpserver.c @@ -24,7 +24,7 @@ #include "apps/dhcpserver.h" -#ifdef LWIP_ESP8266 +#if ESP_DHCP #define BOOTP_BROADCAST 0x8000 @@ -71,10 +71,6 @@ #define DHCPS_STATE_IDLE 5 #define DHCPS_STATE_RELEASE 6 -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - //////////////////////////////////////////////////////////////////////////////////// static const u32_t magic_cookie = 0x63538263; diff --git a/components/lwip/component.mk b/components/lwip/component.mk index 5d15020047..49fc644ae4 100644 --- a/components/lwip/component.mk +++ b/components/lwip/component.mk @@ -8,4 +8,3 @@ COMPONENT_SRCDIRS := api apps/sntp apps core/ipv4 core/ipv6 core netif port/free CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable -include $(IDF_PATH)/make/component_common.mk diff --git a/components/lwip/core/dns.c b/components/lwip/core/dns.c index da8ac95b8d..8f0ac5cc81 100755 --- a/components/lwip/core/dns.c +++ b/components/lwip/core/dns.c @@ -85,10 +85,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - /** Random generator function to create random TXIDs and source ports for queries */ #ifndef DNS_RAND_TXID #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0) @@ -1091,7 +1087,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u8_t dns_err; /* This entry is now completed. */ -#ifndef LWIP_ESP8266 +#if ! ESP_DNS entry->state = DNS_STATE_DONE; #endif dns_err = hdr.flags2 & DNS_FLAG2_ERR_MASK; @@ -1105,7 +1101,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, if (((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) || (dns_err != 0) || (nquestions != 1)) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name)); /* call callback to indicate error, clean up memory and return */ -#ifndef LWIP_ESP8266 +#if ! ESP_DNS goto responseerr; } #else diff --git a/components/lwip/core/init.c b/components/lwip/core/init.c index 2a410d0e46..8b2e92669a 100755 --- a/components/lwip/core/init.c +++ b/components/lwip/core/init.c @@ -61,7 +61,7 @@ #include "lwip/api.h" #include "netif/ppp/ppp_impl.h" -#ifndef PERF +#if ! ESP_PERF /* Compile-time sanity checks for configuration errors. * These can be done independently of LWIP_DEBUG, without penalty. */ @@ -135,21 +135,22 @@ //#endif #else /* LWIP_WND_SCALE */ -#ifndef LWIP_ESP8266 +#if ! ESP_PER_SOC_TCP_WND #if (LWIP_TCP && (TCP_WND > 0xffff)) #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)" #endif #endif #endif /* LWIP_WND_SCALE */ -#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) + +#if ! ESP_PER_SOC_TCP_WND +#if (LWIP_TCP && (TCP_SND_QUEUELEN(0) > 0xffff)) #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" #endif -#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) +#if (LWIP_TCP && (TCP_SND_QUEUELEN(0) < 2)) #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" #endif -#ifndef LWIP_ESP8266 #if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" #endif @@ -285,30 +286,34 @@ /* TCP sanity checks */ #if !LWIP_DISABLE_TCP_SANITY_CHECKS +#if ! ESP_PER_SOC_TCP_WND #if LWIP_TCP -#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) +#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN(0)) #error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif -#if TCP_SND_BUF < (2 * TCP_MSS) + +#if TCP_SND_BUF(0) < (2 * TCP_MSS) #error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif -#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS)) - #error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#if TCP_SND_QUEUELEN(0) < (2 * (TCP_SND_BUF(0) / TCP_MSS)) + #error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF(0)/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif -#if TCP_SNDLOWAT >= TCP_SND_BUF +#if TCP_SNDLOWAT >= TCP_SND_BUF(0) #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS)) #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" #endif -#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN +#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN(0) #error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif +#endif + #if !MEMP_MEM_MALLOC && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) #error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif -#ifndef LWIP_ESP8266 +#if ! ESP_LWIP #if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)))) #error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif @@ -328,13 +333,6 @@ void lwip_init(void) { -#ifdef LWIP_ESP8266 -// MEMP_NUM_TCP_PCB = 5; -// TCP_WND = (4 * TCP_MSS); -// TCP_MAXRTX = 12; -// TCP_SYNMAXRTX = 6; -#endif - /* Modules initialization */ stats_init(); #if !NO_SYS diff --git a/components/lwip/core/ipv4/autoip.c b/components/lwip/core/ipv4/autoip.c index 391e8eeaed..19b1928368 100755 --- a/components/lwip/core/ipv4/autoip.c +++ b/components/lwip/core/ipv4/autoip.c @@ -76,11 +76,6 @@ #include #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /* 169.254.0.0 */ #define AUTOIP_NET 0xA9FE0000 /* 169.254.1.0 */ diff --git a/components/lwip/core/ipv4/dhcp.c b/components/lwip/core/ipv4/dhcp.c index 1f3758fa91..33d13fb326 100755 --- a/components/lwip/core/ipv4/dhcp.c +++ b/components/lwip/core/ipv4/dhcp.c @@ -82,10 +82,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - /** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) */ @@ -146,7 +142,7 @@ static u8_t dhcp_discover_select_options[] = { DHCP_OPTION_BROADCAST, DHCP_OPTION_DNS_SERVER -#ifdef LWIP_ESP8266 +#if ESP_DHCP /**add options for support more router by liuHan**/ , DHCP_OPTION_DOMAIN_NAME, DHCP_OPTION_NB_TINS, @@ -454,7 +450,7 @@ dhcp_fine_tmr(void) /* only act on DHCP configured interfaces */ if (netif->dhcp != NULL) { -//#ifdef LWIP_ESP8266 +//#if ESP_DHCP /*add DHCP retries processing by LiuHan*/ #if 0 if (DHCP_MAXRTX != 0) { @@ -997,7 +993,7 @@ dhcp_discover(struct netif *netif) dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); -#ifdef LWIP_ESP8266 +#if ESP_DHCP #if LWIP_NETIF_HOSTNAME dhcp_option_hostname(dhcp, netif); #endif /* LWIP_NETIF_HOSTNAME */ diff --git a/components/lwip/core/ipv4/icmp.c b/components/lwip/core/ipv4/icmp.c index c492ed75fe..9202bb650c 100755 --- a/components/lwip/core/ipv4/icmp.c +++ b/components/lwip/core/ipv4/icmp.c @@ -51,11 +51,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be * used to modify and send a response packet (and to 1 if this is not the case, * e.g. when link header is stripped of when receiving) */ diff --git a/components/lwip/core/ipv4/igmp.c b/components/lwip/core/ipv4/igmp.c index d75fe15fd0..03f3ae384b 100755 --- a/components/lwip/core/ipv4/igmp.c +++ b/components/lwip/core/ipv4/igmp.c @@ -92,11 +92,6 @@ Steve Reynolds #include "string.h" -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /* * IGMP constants */ diff --git a/components/lwip/core/ipv4/ip4.c b/components/lwip/core/ipv4/ip4.c index 5f1e77a5e7..1d581d4d85 100755 --- a/components/lwip/core/ipv4/ip4.c +++ b/components/lwip/core/ipv4/ip4.c @@ -59,11 +59,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /** Set this to 0 in the rare case of wanting to call an extra function to * generate the IP checksum (in contrast to calculating it on-the-fly). */ #ifndef LWIP_INLINE_IP_CHKSUM @@ -150,7 +145,7 @@ ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src) struct netif * ip4_route(const ip4_addr_t *dest) { -#ifdef LWIP_ESP8266 +#if ESP_LWIP struct netif *non_default_netif = NULL; #endif struct netif *netif; @@ -183,7 +178,7 @@ ip4_route(const ip4_addr_t *dest) } } -#ifdef LWIP_ESP8266 +#if ESP_LWIP if (non_default_netif && !ip4_addr_isbroadcast(dest, non_default_netif)){ return non_default_netif; } diff --git a/components/lwip/core/ipv4/ip4_addr.c b/components/lwip/core/ipv4/ip4_addr.c index 3053cf087e..0501b84e5f 100755 --- a/components/lwip/core/ipv4/ip4_addr.c +++ b/components/lwip/core/ipv4/ip4_addr.c @@ -45,17 +45,8 @@ /* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ -#ifdef LWIP_ESP8266 -//TO_DO -//const ip_addr_t ip_addr_any ICACHE_RODATA_ATTR STORE_ATTR = IPADDR4_INIT(IPADDR_ANY); -//const ip_addr_t ip_addr_broadcast ICACHE_RODATA_ATTR STORE_ATTR = IPADDR4_INIT(IPADDR_BROADCAST); const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY); const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST); -#else -const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY); -const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST); -#endif - /** * Determine if an address is a broadcast address on a network interface @@ -170,7 +161,7 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr) u32_t parts[4]; u32_t *pp = parts; -#ifdef LWIP_ESP8266 +#if ESP_LWIP //#if 0 char ch; unsigned long cutoff; @@ -199,8 +190,7 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr) } } -#ifdef LWIP_ESP8266 -//#if 0 +#if ESP_IP4_ATON cutoff =(unsigned long)0xffffffff / (unsigned long)base; cutlim =(unsigned long)0xffffffff % (unsigned long)base; for (;;) { diff --git a/components/lwip/core/ipv4/ip_frag.c b/components/lwip/core/ipv4/ip_frag.c index 1e6b053e6f..a647433506 100755 --- a/components/lwip/core/ipv4/ip_frag.c +++ b/components/lwip/core/ipv4/ip_frag.c @@ -51,11 +51,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - #if IP_REASSEMBLY /** * The IP reassembly code currently has the following limitations: diff --git a/components/lwip/core/ipv6/icmp6.c b/components/lwip/core/ipv6/icmp6.c index 0a17da33e1..013983bde1 100755 --- a/components/lwip/core/ipv6/icmp6.c +++ b/components/lwip/core/ipv6/icmp6.c @@ -56,10 +56,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - #ifndef LWIP_ICMP6_DATASIZE #define LWIP_ICMP6_DATASIZE 8 #endif diff --git a/components/lwip/core/ipv6/ip6.c b/components/lwip/core/ipv6/ip6.c index 056d33355f..380bc290cd 100755 --- a/components/lwip/core/ipv6/ip6.c +++ b/components/lwip/core/ipv6/ip6.c @@ -59,10 +59,6 @@ #include "lwip/debug.h" #include "lwip/stats.h" -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - /** * Finds the appropriate network interface for a given IPv6 address. It tries to select * a netif following a sequence of heuristics: diff --git a/components/lwip/core/ipv6/ip6_frag.c b/components/lwip/core/ipv6/ip6_frag.c index 0792c2e1be..c9e13cd208 100755 --- a/components/lwip/core/ipv6/ip6_frag.c +++ b/components/lwip/core/ipv6/ip6_frag.c @@ -52,11 +52,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - #if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ diff --git a/components/lwip/core/ipv6/mld6.c b/components/lwip/core/ipv6/mld6.c index 6a2d55c549..489c5063a7 100755 --- a/components/lwip/core/ipv6/mld6.c +++ b/components/lwip/core/ipv6/mld6.c @@ -59,11 +59,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /* * MLD constants */ diff --git a/components/lwip/core/ipv6/nd6.c b/components/lwip/core/ipv6/nd6.c index 39e7bfed03..36f8f78c35 100755 --- a/components/lwip/core/ipv6/nd6.c +++ b/components/lwip/core/ipv6/nd6.c @@ -60,11 +60,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /* Router tables. */ struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; diff --git a/components/lwip/core/mem.c b/components/lwip/core/mem.c index 42df6daeba..9ca9e3c4fc 100755 --- a/components/lwip/core/mem.c +++ b/components/lwip/core/mem.c @@ -65,10 +65,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - #if MEM_USE_POOLS #if MEMP_MEM_MALLOC diff --git a/components/lwip/core/memp.c b/components/lwip/core/memp.c index a5169abc81..7895533652 100755 --- a/components/lwip/core/memp.c +++ b/components/lwip/core/memp.c @@ -70,10 +70,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) #include "lwip/priv/memp_std.h" diff --git a/components/lwip/core/netif.c b/components/lwip/core/netif.c index 33e030412a..5c308a957c 100755 --- a/components/lwip/core/netif.c +++ b/components/lwip/core/netif.c @@ -81,10 +81,6 @@ #define NETIF_LINK_CALLBACK(n) #endif /* LWIP_NETIF_LINK_CALLBACK */ -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - struct netif *netif_list; struct netif *netif_default; @@ -220,7 +216,7 @@ netif_add(struct netif *netif, /* netif not under DHCP control by default */ netif->dhcp = NULL; -#ifdef LWIP_ESP8266 +#if ESP_DHCP netif->dhcps_pcb = NULL; #endif @@ -233,8 +229,7 @@ netif_add(struct netif *netif, #endif /* LWIP_AUTOIP */ #if LWIP_IPV6_AUTOCONFIG -#ifdef LWIP_ESP8266 -//#if 0 +#if ESP_IPV6_AUTOCONFIG netif->ip6_autoconfig_enabled = 1; #else /* IPv6 address autoconfiguration not enabled by default */ @@ -973,7 +968,7 @@ netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit) } } -#ifdef LWIP_ESP8266 +#if ESP_LWIP ip6_addr_set( ip_2_ip6(&netif->link_local_addr), ip_2_ip6(&netif->ip6_addr[0]) ); #endif @@ -1028,7 +1023,7 @@ netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chos } -#ifdef LWIP_ESP8266 +#if ESP_LWIP void netif_create_ip4_linklocal_address(struct netif * netif) { diff --git a/components/lwip/core/pbuf.c b/components/lwip/core/pbuf.c index e35f8a6b7f..29e24ef2b4 100755 --- a/components/lwip/core/pbuf.c +++ b/components/lwip/core/pbuf.c @@ -78,12 +78,8 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - -#ifdef LWIP_ESP8266 -#define EP_OFFSET 0 +#if ESP_LWIP +#include "esp_wifi_internal.h" #endif #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) @@ -207,12 +203,7 @@ struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { struct pbuf *p, *q, *r; - -#ifdef LWIP_ESP8266 - u16_t offset = 0; -#else - u16_t offset; -#endif + u16_t offset = 0; s32_t rem_len; /* remaining length */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); @@ -223,48 +214,16 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) /* add room for transport (often TCP) layer header */ offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; -#ifdef LWIP_ESP8266 //TO_DO - offset += EP_OFFSET; -#endif - break; case PBUF_IP: /* add room for IP layer header */ offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN; -#ifdef LWIP_ESP8266 //TO_DO - offset += EP_OFFSET; -#endif - break; case PBUF_LINK: /* add room for link layer header */ offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; -#ifdef LWIP_ESP8266 //TO_DO - /* - * 1. LINK_HLEN 14Byte will be remove in WLAN layer - * 2. IEEE80211_HDR_MAX_LEN needs 40 bytes. - * 3. encryption needs exra 4 bytes ahead of actual data payload, and require - * DAddr and SAddr to be 4-byte aligned. - * 4. TRANSPORT and IP are all 20, 4 bytes aligned, nice... - * 5. LCC add 6 bytes more, We don't consider WAPI yet... - * 6. define LWIP_MEM_ALIGN to be 4 Byte aligned, pbuf struct is 16B, Only thing may be - * matter is ether_hdr is not 4B aligned. - * - * So, we need extra (40 + 4 - 14) = 30 and it's happen to be 4-Byte aligned - * - * 1. lwip - * | empty 30B | eth_hdr (14B) | payload ...| - * total: 44B ahead payload - * 2. net80211 - * | max 80211 hdr, 32B | ccmp/tkip iv (8B) | sec rsv(4B) | payload ...| - * total: 40B ahead sec_rsv and 44B ahead payload - * - */ - offset += EP_OFFSET; //remove LINK hdr in wlan -#endif - break; case PBUF_RAW_TX: /* add room for encapsulating link layer headers (e.g. 802.11) */ @@ -273,10 +232,6 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) case PBUF_RAW: offset = 0; -#ifdef LWIP_ESP8266 //TO_DO - offset += EP_OFFSET; -#endif - break; default: LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); @@ -395,9 +350,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) /* set flags */ p->flags = 0; -#ifdef LWIP_ESP8266 +#if ESP_LWIP p->eb = NULL; #endif + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); return p; } @@ -763,9 +719,8 @@ pbuf_free(struct pbuf *p) /* is this a ROM or RAM referencing pbuf? */ } else if (type == PBUF_ROM || type == PBUF_REF) { -#ifdef LWIP_ESP8266 - extern void system_pp_recycle_rx_pkt(void*); - if (type == PBUF_REF && p->eb != NULL ) system_pp_recycle_rx_pkt(p->eb); +#if ESP_LWIP + if (type == PBUF_REF && p->eb != NULL ) esp_wifi_internal_free_rx_buffer(p->eb); #endif memp_free(MEMP_PBUF, p); diff --git a/components/lwip/core/raw.c b/components/lwip/core/raw.c index 72a58d381d..82ce4e3a73 100755 --- a/components/lwip/core/raw.c +++ b/components/lwip/core/raw.c @@ -54,10 +54,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - /** The list of RAW PCBs */ static struct raw_pcb *raw_pcbs; diff --git a/components/lwip/core/stats.c b/components/lwip/core/stats.c index 77ac3c675e..b47ab0b7fa 100755 --- a/components/lwip/core/stats.c +++ b/components/lwip/core/stats.c @@ -47,10 +47,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - struct stats_ lwip_stats; #if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY diff --git a/components/lwip/core/tcp.c b/components/lwip/core/tcp.c index e8fda52c8d..627df6d293 100755 --- a/components/lwip/core/tcp.c +++ b/components/lwip/core/tcp.c @@ -57,10 +57,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - #ifndef TCP_LOCAL_PORT_RANGE_START /* From http://www.iana.org/assignments/port-numbers: "The Dynamic and/or Private Ports are those from 49152 through 65535" */ @@ -77,14 +73,7 @@ static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; #define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT #endif /* LWIP_TCP_KEEPALIVE */ -#ifdef LWIP_ESP8266 -//TO_DO -//char tcp_state_str[12]; -//const char tcp_state_str_rodata[][12] ICACHE_RODATA_ATTR STORE_ATTR = { const char * const tcp_state_str[] = { -#else -const char * const tcp_state_str[] = { -#endif "CLOSED", "LISTEN", "SYN_SENT", @@ -100,27 +89,14 @@ const char * const tcp_state_str[] = { /* last local TCP port */ -#ifdef LWIP_ESP8266 static s16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; -#else -static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; -#endif /* Incremented every coarse grained timer shot (typically every 500 ms). */ u32_t tcp_ticks; -#ifdef LWIP_ESP8266 -//TO_DO -//const u8_t tcp_backoff[13] ICACHE_RODATA_ATTR STORE_ATTR ={ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; -//const u8_t tcp_persist_backoff[7] ICACHE_RODATA_ATTR STORE_ATTR = { 3, 6, 12, 24, 48, 96, 120 }; - -const u8_t tcp_backoff[13] = { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; -const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; -#else const u8_t tcp_backoff[13] = { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; /* Times per slowtmr hits */ const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; -#endif /* The TCP PCB lists. */ @@ -136,19 +112,9 @@ struct tcp_pcb *tcp_active_pcbs; struct tcp_pcb *tcp_tw_pcbs; /** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ -#ifdef LWIP_ESP8266 -//TO_DO -//struct tcp_pcb ** const tcp_pcb_lists[] ICACHE_RODATA_ATTR STORE_ATTR = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, - // &tcp_active_pcbs, &tcp_tw_pcbs}; struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs}; -#else -struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, - &tcp_active_pcbs, &tcp_tw_pcbs}; -#endif - - u8_t tcp_active_pcbs_changed; /** Timer counter to handle calling slow-timer from tcp_tmr() */ @@ -638,7 +604,7 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) { u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; - if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { + if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND(pcb) / 2), pcb->mss))) { /* we can advertise more window */ pcb->rcv_ann_wnd = pcb->rcv_wnd; return new_right_edge - pcb->rcv_ann_right_edge; @@ -694,10 +660,10 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len) wnd_inflation = tcp_update_rcv_ann_wnd(pcb); /* If the change in the right edge of window is significant (default - * watermark is TCP_WND/4), then send an explicit update now. + * watermark is TCP_WND(pcb)/4), then send an explicit update now. * Otherwise wait for a packet to be sent in the normal course of * events (or more window to be available later) */ - if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { + if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD(pcb)) { tcp_ack_now(pcb); tcp_output(pcb); } @@ -720,7 +686,7 @@ tcp_new_port(void) again: -#ifdef LWIP_ESP8266 +#if ESP_RANDOM_TCP_PORT tcp_port = system_get_time(); if (tcp_port < 0) tcp_port = LWIP_RAND() - tcp_port; @@ -827,9 +793,9 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, pcb->snd_lbb = iss - 1; /* Start with a window that does not need scaling. When window scaling is enabled and used, the window is enlarged when both sides agree on scaling. */ - pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND(pcb)); pcb->rcv_ann_right_edge = pcb->rcv_nxt; - pcb->snd_wnd = TCP_WND; + pcb->snd_wnd = TCP_WND(pcb); /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; @@ -837,7 +803,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; - pcb->ssthresh = TCP_WND; + pcb->ssthresh = TCP_WND(pcb); #if LWIP_CALLBACK_API pcb->connected = connected; #else /* LWIP_CALLBACK_API */ @@ -915,13 +881,7 @@ tcp_slowtmr_start: /* If snd_wnd is zero, use persist timer to send 1 byte probes * instead of using the standard retransmission mechanism. */ -#ifdef LWIP_ESP8266 -//NEED TO DO - //u8_t backoff_cnt = system_get_data_of_array_8(tcp_persist_backoff, pcb->persist_backoff-1); u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff-1]; -#else - u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff-1]; -#endif if (pcb->persist_cnt < backoff_cnt) { pcb->persist_cnt++; @@ -949,15 +909,7 @@ tcp_slowtmr_start: /* Double retransmission time-out unless we are trying to * connect to somebody (i.e., we are in SYN_SENT). */ if (pcb->state != SYN_SENT) { - -#ifdef LWIP_ESP8266 -//TO_DO -// pcb->rto = ((pcb->sa >> 3) + pcb->sv) << system_get_data_of_array_8(tcp_backoff, pcb->nrtx); pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; -#else - pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; -#endif - } /* Reset the retransmission timer. */ @@ -1436,7 +1388,7 @@ tcp_kill_timewait(void) } } -#ifdef LWIP_ESP8266 +#if ESP_LWIP /** * Kills the oldest connection that is in FIN_WAIT_2 state. * Called from tcp_alloc() if no more connections are available. @@ -1502,7 +1454,7 @@ tcp_alloc(u8_t prio) struct tcp_pcb *pcb; u32_t iss; -#ifdef LWIP_ESP8266 +#if ESP_LWIP /*Kills the oldest connection that is in TIME_WAIT state.*/ u8_t time_wait_num = 0; for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { @@ -1580,12 +1532,18 @@ tcp_alloc(u8_t prio) } if (pcb != NULL) { memset(pcb, 0, sizeof(struct tcp_pcb)); + +#if ESP_PER_SOC_TCP_WND + pcb->per_soc_tcp_wnd = TCP_WND_DEFAULT; + pcb->per_soc_tcp_snd_buf = TCP_SND_BUF_DEFAULT; +#endif + pcb->prio = prio; - pcb->snd_buf = TCP_SND_BUF; + pcb->snd_buf = TCP_SND_BUF_DEFAULT; pcb->snd_queuelen = 0; /* Start with a window that does not need scaling. When window scaling is enabled and used, the window is enlarged when both sides agree on scaling. */ - pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND(pcb)); #if LWIP_WND_SCALE /* snd_scale and rcv_scale are zero unless both sides agree to use scaling */ pcb->snd_scale = 0; @@ -1608,7 +1566,6 @@ tcp_alloc(u8_t prio) pcb->snd_lbb = iss; pcb->tmr = tcp_ticks; pcb->last_timer = tcp_timer_ctr; - pcb->polltmr = 0; #if LWIP_CALLBACK_API @@ -1625,6 +1582,7 @@ tcp_alloc(u8_t prio) pcb->keep_cnt_sent = 0; } + return pcb; } @@ -2010,14 +1968,7 @@ void tcp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* n const char* tcp_debug_state_str(enum tcp_state s) { -#ifdef LWIP_ESP8266 -//TO_DO - //system_get_string_from_flash(tcp_state_str_rodata[s], tcp_state_str, 12); - //return tcp_state_str; return tcp_state_str[s]; -#else - return tcp_state_str[s]; -#endif } #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG diff --git a/components/lwip/core/tcp_in.c b/components/lwip/core/tcp_in.c index 25d7403851..f3284233e7 100755 --- a/components/lwip/core/tcp_in.c +++ b/components/lwip/core/tcp_in.c @@ -60,11 +60,6 @@ #include "lwip/nd6.h" #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /** Initial CWND calculation as defined RFC 2581 */ #define LWIP_TCP_CALC_INITIAL_CWND(mss) LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U)); /** Initial slow start threshold value: we use the full window */ @@ -329,20 +324,6 @@ tcp_input(struct pbuf *p, struct netif *inp) if (pcb != NULL) { - -#ifdef LWIP_ESP8266 -//No Need Any more -/* - extern char RxNodeNum(void); - if(RxNodeNum() <= 2) - { -extern void pbuf_free_ooseq(void); - pbuf_free_ooseq(); - } -*/ -#endif - - /* The incoming segment belongs to a connection. */ #if TCP_INPUT_DEBUG tcp_debug_print_state(pcb->state); @@ -1745,9 +1726,9 @@ tcp_parseopt(struct tcp_pcb *pcb) pcb->rcv_scale = TCP_RCV_SCALE; pcb->flags |= TF_WND_SCALE; /* window scaling is enabled, we can use the full receive window */ - LWIP_ASSERT("window not at default value", pcb->rcv_wnd == TCPWND_MIN16(TCP_WND)); - LWIP_ASSERT("window not at default value", pcb->rcv_ann_wnd == TCPWND_MIN16(TCP_WND)); - pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND; + LWIP_ASSERT("window not at default value", pcb->rcv_wnd == TCPWND_MIN16(TCP_WND(pcb))); + LWIP_ASSERT("window not at default value", pcb->rcv_ann_wnd == TCPWND_MIN16(TCP_WND(pcb))); + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND(pcb); } break; #endif diff --git a/components/lwip/core/tcp_out.c b/components/lwip/core/tcp_out.c index aac02e4ebe..35a8aa145d 100755 --- a/components/lwip/core/tcp_out.c +++ b/components/lwip/core/tcp_out.c @@ -59,10 +59,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - /* Define some copy-macros for checksum-on-copy so that the code looks nicer by preventing too many ifdef's. */ #if TCP_CHECKSUM_ON_COPY @@ -336,9 +332,9 @@ tcp_write_checks(struct tcp_pcb *pcb, u16_t len) /* If total number of pbufs on the unsent/unacked queues exceeds the * configured maximum, return an error */ /* check for configured max queuelen and possible overflow */ - if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN(pcb)) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n", - pcb->snd_queuelen, TCP_SND_QUEUELEN)); + pcb->snd_queuelen, TCP_SND_QUEUELEN(pcb))); TCP_STATS_INC(tcp.memerr); pcb->flags |= TF_NAGLEMEMERR; return ERR_MEM; @@ -606,9 +602,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) /* Now that there are more segments queued, we check again if the * length of the queue exceeds the configured maximum or * overflows. */ - if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + if ((queuelen > TCP_SND_QUEUELEN(pcb)) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n", - queuelen, (int)TCP_SND_QUEUELEN)); + queuelen, (int)TCP_SND_QUEUELEN(pcb))); pbuf_free(p); goto memerr; } @@ -766,10 +762,10 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) (flags & (TCP_SYN | TCP_FIN)) != 0); /* check for configured max queuelen and possible overflow (FIN flag should always come through!) */ - if (((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) && + if (((pcb->snd_queuelen >= TCP_SND_QUEUELEN(pcb)) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) && ((flags & TCP_FIN) == 0)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n", - pcb->snd_queuelen, TCP_SND_QUEUELEN)); + pcb->snd_queuelen, TCP_SND_QUEUELEN(pcb))); TCP_STATS_INC(tcp.memerr); pcb->flags |= TF_NAGLEMEMERR; return ERR_MEM; @@ -1301,6 +1297,7 @@ tcp_rst(u32_t seqno, u32_t ackno, struct pbuf *p; struct tcp_hdr *tcphdr; struct netif *netif; + p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); if (p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); @@ -1315,10 +1312,18 @@ tcp_rst(u32_t seqno, u32_t ackno, tcphdr->seqno = htonl(seqno); tcphdr->ackno = htonl(ackno); TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); +#if ESP_PER_SOC_TCP_WND #if LWIP_WND_SCALE - tcphdr->wnd = PP_HTONS(((TCP_WND >> TCP_RCV_SCALE) & 0xFFFF)); + tcphdr->wnd = PP_HTONS(((TCP_WND_DEFAULT >> TCP_RCV_SCALE) & 0xFFFF)); #else - tcphdr->wnd = PP_HTONS(TCP_WND); + tcphdr->wnd = PP_HTONS(TCP_WND_DEFAULT); +#endif +#else +#if LWIP_WND_SCALE + tcphdr->wnd = PP_HTONS(((TCP_WND_DEFAULT >> TCP_RCV_SCALE) & 0xFFFF)); +#else + tcphdr->wnd = PP_HTONS(TCP_WND_DEFAULT); +#endif #endif tcphdr->chksum = 0; tcphdr->urgp = 0; diff --git a/components/lwip/core/timers.c b/components/lwip/core/timers.c index 0a361474eb..ef47b2e187 100755 --- a/components/lwip/core/timers.c +++ b/components/lwip/core/timers.c @@ -62,11 +62,6 @@ #include "lwip/sys.h" #include "lwip/pbuf.h" -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - /** The one and only timeout list */ static struct sys_timeo *next_timeout; #if NO_SYS @@ -162,7 +157,7 @@ dhcp_timer_coarse(void *arg) LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); dhcp_coarse_tmr(); -#ifdef LWIP_ESP8266 +#if ESP_DHCP extern void dhcps_coarse_tmr(void); dhcps_coarse_tmr(); #endif @@ -294,12 +289,6 @@ void sys_timeouts_init(void) #endif /* LWIP_ARP */ #if LWIP_DHCP -#ifdef LWIP_ESP8266 - // DHCP_MAXRTX = 0; -#endif - - - sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); #endif /* LWIP_DHCP */ @@ -346,7 +335,7 @@ void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) #else /* LWIP_DEBUG_TIMERNAMES */ -#ifdef LWIP_ESP8266 +#if ESP_LIGHT_SLEEP u32_t LwipTimOutLim = 0; // For light sleep. time out. limit is 3000ms #endif @@ -379,7 +368,7 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) timeout->h = handler; timeout->arg = arg; -#ifdef LWIP_ESP8266 +#if ESP_LIGHT_SLEEP if(msecs < LwipTimOutLim) msecs = LwipTimOutLim; #endif diff --git a/components/lwip/core/udp.c b/components/lwip/core/udp.c index e44ab7e73d..37ae2c1796 100755 --- a/components/lwip/core/udp.c +++ b/components/lwip/core/udp.c @@ -67,11 +67,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - - #ifndef UDP_LOCAL_PORT_RANGE_START /* From http://www.iana.org/assignments/port-numbers: "The Dynamic and/or Private Ports are those from 49152 through 65535" */ diff --git a/components/lwip/include/lwip/lwip/api.h b/components/lwip/include/lwip/lwip/api.h index 985eb76d4a..5b6a21ecf3 100755 --- a/components/lwip/include/lwip/lwip/api.h +++ b/components/lwip/include/lwip/lwip/api.h @@ -185,10 +185,6 @@ struct netconn { /** sem that is used to synchronously execute functions in the core context */ sys_sem_t op_completed; -#ifdef LWIP_ESP8266 - sys_sem_t snd_op_completed; //only for snd semphore -#endif - #endif /** mbox where received packets are stored until they are fetched diff --git a/components/lwip/include/lwip/lwip/dhcp.h b/components/lwip/include/lwip/lwip/dhcp.h index 2d8926eca6..76ce1543ff 100755 --- a/components/lwip/include/lwip/lwip/dhcp.h +++ b/components/lwip/include/lwip/lwip/dhcp.h @@ -249,7 +249,7 @@ void dhcp_fine_tmr(void); #define DHCP_OPTION_NTP 42 #define DHCP_OPTION_END 255 -#ifdef LWIP_ESP8266 +#if ESP_LWIP /**add options for support more router by liuHan**/ #define DHCP_OPTION_DOMAIN_NAME 15 #define DHCP_OPTION_PRD 31 diff --git a/components/lwip/include/lwip/lwip/dns.h b/components/lwip/include/lwip/lwip/dns.h index 1ceed0d883..5ef12e56c2 100755 --- a/components/lwip/include/lwip/lwip/dns.h +++ b/components/lwip/include/lwip/lwip/dns.h @@ -36,7 +36,7 @@ #include "lwip/opt.h" -#ifdef LWIP_ESP8266 +#if ESP_DNS #include "lwip/err.h" #endif diff --git a/components/lwip/include/lwip/lwip/err.h b/components/lwip/include/lwip/lwip/err.h index 26fb91db9b..a766ee186d 100755 --- a/components/lwip/include/lwip/lwip/err.h +++ b/components/lwip/include/lwip/lwip/err.h @@ -60,7 +60,7 @@ typedef s8_t err_t; #define ERR_USE -8 /* Address in use. */ -#ifdef LWIP_ESP8266 +#if ESP_LWIP #define ERR_ALREADY -9 /* Already connected. */ #define ERR_ISCONN -10 /* Conn already established.*/ #define ERR_IS_FATAL(e) ((e) < ERR_ISCONN) diff --git a/components/lwip/include/lwip/lwip/mem.h b/components/lwip/include/lwip/lwip/mem.h index ca76f66322..a90d07256b 100755 --- a/components/lwip/include/lwip/lwip/mem.h +++ b/components/lwip/include/lwip/lwip/mem.h @@ -51,8 +51,6 @@ typedef size_t mem_size_t; * allow these defines to be overridden. */ -#ifndef MEMLEAK_DEBUG - #ifndef mem_free #define mem_free free #endif @@ -63,41 +61,6 @@ typedef size_t mem_size_t; #define mem_calloc calloc #endif -/* DYC_NEED_TO_DO_LATER -#ifndef mem_realloc -#define mem_realloc -#endif -#ifndef mem_zalloc -#define mem_zalloc -#endif -*/ - -#else -/* -#ifndef mem_free -#define mem_free(s) \ - do{\ - const char *file = mem_debug_file;\ - vPortFree(s, file, __LINE__);\ - }while(0) -#endif -#ifndef mem_malloc -#define mem_malloc(s) ({const char *file = mem_debug_file; pvPortMalloc(s, file, __LINE__);}) -#endif -#ifndef mem_calloc -#define mem_calloc(s) ({const char *file = mem_debug_file; pvPortCalloc(s, file, __LINE__);}) -#endif -#ifndef mem_realloc -#define mem_realloc(p, s) ({const char *file = mem_debug_file; pvPortRealloc(p, s, file, __LINE__);}) -#endif -#ifndef mem_zalloc -#define mem_zalloc(s) ({const char *file = mem_debug_file; pvPortZalloc(s, file, __LINE__);}) -#endif -*/ -#endif - - - /* Since there is no C library allocation function to shrink memory without moving it, define this to nothing. */ #ifndef mem_trim diff --git a/components/lwip/include/lwip/lwip/netif.h b/components/lwip/include/lwip/lwip/netif.h index 99066a5a1f..666f77eb96 100755 --- a/components/lwip/include/lwip/lwip/netif.h +++ b/components/lwip/include/lwip/lwip/netif.h @@ -177,7 +177,7 @@ typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif, #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ -#ifdef LWIP_ESP8266 +#if ESP_DHCP /*add DHCP event processing by LiuHan*/ typedef void (*dhcp_event_fn)(void); #endif @@ -190,7 +190,7 @@ struct netif { /** pointer to next in linked list */ struct netif *next; -#ifdef LWIP_ESP8266 +#if ESP_LWIP //ip_addr_t is changed by marco IPV4, IPV6 ip_addr_t link_local_addr; #endif @@ -248,7 +248,7 @@ struct netif { /** the DHCP client state information for this netif */ struct dhcp *dhcp; -#ifdef LWIP_ESP8266 +#if ESP_LWIP struct udp_pcb *dhcps_pcb; dhcp_event_fn dhcp_event; #endif diff --git a/components/lwip/include/lwip/lwip/opt.h b/components/lwip/include/lwip/lwip/opt.h index 76fff88052..51d340e00b 100755 --- a/components/lwip/include/lwip/lwip/opt.h +++ b/components/lwip/include/lwip/lwip/opt.h @@ -986,7 +986,7 @@ * (2 * TCP_MSS) for things to work well */ #ifndef TCP_WND -#define TCP_WND (4 * TCP_MSS) +#define TCP_WND(pcb) (4 * TCP_MSS) #endif /** @@ -1040,7 +1040,7 @@ * To achieve good performance, this should be at least 2 * TCP_MSS. */ #ifndef TCP_SND_BUF -#define TCP_SND_BUF (2 * TCP_MSS) +#define TCP_SND_BUF(pcb) (2 * TCP_MSS) #endif /** @@ -1048,7 +1048,7 @@ * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */ #ifndef TCP_SND_QUEUELEN -#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#define TCP_SND_QUEUELEN(pcb) ((4 * (TCP_SND_BUF((pcb))) + (TCP_MSS - 1))/(TCP_MSS)) #endif /** @@ -1057,7 +1057,7 @@ * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). */ #ifndef TCP_SNDLOWAT -#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#define TCP_SNDLOWAT(pcb) LWIP_MIN(LWIP_MAX(((TCP_SND_BUF((pcb)))/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF((pcb))) - 1) #endif /** @@ -1066,7 +1066,7 @@ * this number, select returns writable (combined with TCP_SNDLOWAT). */ #ifndef TCP_SNDQUEUELOWAT -#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#define TCP_SNDQUEUELOWAT(pcb) LWIP_MAX(((TCP_SND_QUEUELEN((pcb)))/2), 5) #endif /** @@ -1134,7 +1134,7 @@ * explicit window update */ #ifndef TCP_WND_UPDATE_THRESHOLD -#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#define TCP_WND_UPDATE_THRESHOLD(pcb) LWIP_MIN((TCP_WND((pcb)) / 4), (TCP_MSS * 4)) #endif /** @@ -3008,8 +3008,8 @@ #define LWIP_PERF 0 #endif -#ifndef THREAD_SAFE_DEBUG -#define THREAD_SAFE_DEBUG 0 +#ifndef ESP_THREAD_SAFE_DEBUG +#define ESP_THREAD_SAFE_DEBUG 0 #endif #endif /* LWIP_HDR_OPT_H */ diff --git a/components/lwip/include/lwip/lwip/pbuf.h b/components/lwip/include/lwip/lwip/pbuf.h index aaf5e294af..1834c4e04c 100755 --- a/components/lwip/include/lwip/lwip/pbuf.h +++ b/components/lwip/include/lwip/lwip/pbuf.h @@ -137,7 +137,7 @@ struct pbuf { */ u16_t ref; -#ifdef LWIP_ESP8266 +#if ESP_LWIP void *eb; #endif }; diff --git a/components/lwip/include/lwip/lwip/priv/api_msg.h b/components/lwip/include/lwip/lwip/priv/api_msg.h index 329fa0de30..02d191a53c 100755 --- a/components/lwip/include/lwip/lwip/priv/api_msg.h +++ b/components/lwip/include/lwip/lwip/priv/api_msg.h @@ -187,7 +187,7 @@ struct dns_api_msg { #endif /* LWIP_DNS */ #if LWIP_NETCONN_SEM_PER_THREAD -#ifdef LWIP_ESP8266 +#if ESP_THREAD_SAFE #define LWIP_NETCONN_THREAD_SEM_GET() sys_thread_sem_get() #define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_thread_sem_init() #define LWIP_NETCONN_THREAD_SEM_FREE() sys_thread_sem_deinit() @@ -222,10 +222,6 @@ struct dns_api_msg { #define TCPIP_APIMSG(m,f,e) do { (m)->function = f; (e) = tcpip_apimsg(m); } while(0) #define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) -#ifdef LWIP_ESP8266 -#define TCPIP_APIMSG_ACK_SND(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SND_SEM(m)); } while(0) -#endif - #endif /* LWIP_TCPIP_CORE_LOCKING */ void lwip_netconn_do_newconn (void *m); diff --git a/components/lwip/include/lwip/lwip/priv/tcp_priv.h b/components/lwip/include/lwip/lwip/priv/tcp_priv.h index b5261b445c..0c498944b3 100755 --- a/components/lwip/include/lwip/lwip/priv/tcp_priv.h +++ b/components/lwip/include/lwip/lwip/priv/tcp_priv.h @@ -92,7 +92,7 @@ err_t tcp_process_refused_data(struct tcp_pcb *pcb); ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ ((tpcb)->unsent->len >= (tpcb)->mss))) || \ - ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \ + ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN(tpcb))) \ ) ? 1 : 0) #define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) diff --git a/components/lwip/include/lwip/lwip/sockets.h b/components/lwip/include/lwip/lwip/sockets.h index aafb3d5cf3..d9622ea03d 100755 --- a/components/lwip/include/lwip/lwip/sockets.h +++ b/components/lwip/include/lwip/lwip/sockets.h @@ -190,7 +190,6 @@ struct msghdr { #define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ #define SO_NO_CHECK 0x100a /* don't create UDP checksum */ - /* * Structure used for manipulating linger option. */ @@ -250,6 +249,11 @@ struct linger { #define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ #define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ #define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ +#if ESP_PER_SOC_TCP_WND +#define TCP_WINDOW 0x06 /* set pcb->per_soc_tcp_wnd */ +#define TCP_SNDBUF 0x07 /* set pcb->per_soc_tcp_snd_buf */ +#endif + #endif /* LWIP_TCP */ #if LWIP_IPV6 @@ -505,7 +509,7 @@ int lwip_fcntl(int s, int cmd, int val); #if LWIP_COMPAT_SOCKETS #if LWIP_COMPAT_SOCKETS != 2 -#if LWIP_THREAD_SAFE +#if ESP_THREAD_SAFE int lwip_accept_r(int s, struct sockaddr *addr, socklen_t *addrlen); int lwip_bind_r(int s, const struct sockaddr *name, socklen_t namelen); @@ -590,7 +594,7 @@ int lwip_fcntl_r(int s, int cmd, int val); #define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) #define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) #endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ -#endif /* LWIP_THREAD_SAFE */ +#endif /* ESP_THREAD_SAFE */ #endif /* LWIP_COMPAT_SOCKETS != 2 */ diff --git a/components/lwip/include/lwip/lwip/tcp.h b/components/lwip/include/lwip/lwip/tcp.h index d52040f99c..6b8c4b6c48 100755 --- a/components/lwip/include/lwip/lwip/tcp.h +++ b/components/lwip/include/lwip/lwip/tcp.h @@ -129,14 +129,14 @@ typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); #define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale)) #define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale)) #define TCPWND16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) -#define TCP_WND_MAX(pcb) ((tcpwnd_size_t)(((pcb)->flags & TF_WND_SCALE) ? TCP_WND : TCPWND16(TCP_WND))) +#define TCP_WND_MAX(pcb) ((tcpwnd_size_t)(((pcb)->flags & TF_WND_SCALE) ? TCP_WND(pcb) : TCPWND16(TCP_WND(pcb)))) typedef u32_t tcpwnd_size_t; typedef u16_t tcpflags_t; #else #define RCV_WND_SCALE(pcb, wnd) (wnd) #define SND_WND_SCALE(pcb, wnd) (wnd) #define TCPWND16(x) (x) -#define TCP_WND_MAX(pcb) TCP_WND +#define TCP_WND_MAX(pcb) TCP_WND(pcb) typedef u16_t tcpwnd_size_t; typedef u8_t tcpflags_t; #endif @@ -236,6 +236,11 @@ struct tcp_pcb { u8_t dupacks; u32_t lastack; /* Highest acknowledged seqno. */ +#if ESP_PER_SOC_TCP_WND + tcpwnd_size_t per_soc_tcp_wnd; /* per tcp socket tcp window size */ + tcpwnd_size_t per_soc_tcp_snd_buf; /* per tcp socket tcp send buffer size */ +#endif + /* congestion avoidance/control variables */ tcpwnd_size_t cwnd; tcpwnd_size_t ssthresh; @@ -402,6 +407,10 @@ const char* tcp_debug_state_str(enum tcp_state s); /* for compatibility with older implementation */ #define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) +#if ESP_PER_SOC_TCP_WND +#define PER_SOC_WND(pcb) (pcb->per_soc_wnd) +#endif + #ifdef __cplusplus } #endif diff --git a/components/lwip/include/lwip/port/lwipopts.h b/components/lwip/include/lwip/port/lwipopts.h index 2c24b2be92..d06e756850 100755 --- a/components/lwip/include/lwip/port/lwipopts.h +++ b/components/lwip/include/lwip/port/lwipopts.h @@ -33,11 +33,13 @@ #define __LWIPOPTS_H__ #include +#include +#include +#include #include "esp_task.h" #include "sdkconfig.h" /* Enable all Espressif-only options */ -#define LWIP_ESP8266 /* ----------------------------------------------- @@ -96,17 +98,37 @@ extern unsigned long os_random(void); ---------- Internal Memory Pool Sizes ---------- ------------------------------------------------ */ -/** - * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. - * (requires the LWIP_TCP option) - */ -#define MEMP_NUM_TCP_PCB 5 /** * MEMP_NUM_NETCONN: the number of struct netconns. * (only needed if you use the sequential API, like api_lib.c) */ -#define MEMP_NUM_NETCONN 10 +#define MEMP_NUM_NETCONN CONFIG_LWIP_MAX_SOCKETS + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#define MEMP_NUM_RAW_PCB 16 + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB 16 + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB_LISTEN 16 + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#define MEMP_NUM_UDP_PCB 16 /* -------------------------------- @@ -221,23 +243,6 @@ extern unsigned long os_random(void); ---------- TCP options ---------- --------------------------------- */ -/** - * TCP_WND: The size of a TCP window. This must be at least - * (2 * TCP_MSS) for things to work well - */ -#define PERF 1 -#ifdef PERF -extern unsigned char misc_prof_get_tcpw(void); -extern unsigned char misc_prof_get_tcp_snd_buf(void); -#define TCP_WND (misc_prof_get_tcpw()*TCP_MSS) -#define TCP_SND_BUF (misc_prof_get_tcp_snd_buf()*TCP_MSS) - -#else - -#define TCP_WND (4 * TCP_MSS) -#define TCP_SND_BUF (2 * TCP_MSS) - -#endif /** @@ -507,24 +512,65 @@ extern unsigned char misc_prof_get_tcp_snd_buf(void); */ #define TCPIP_DEBUG LWIP_DBG_OFF +/* Enable all Espressif-only options */ + +#define ESP_LWIP 1 +#define ESP_PER_SOC_TCP_WND 1 +#define ESP_THREAD_SAFE 1 +#define ESP_THREAD_SAFE_DEBUG LWIP_DBG_OFF +#define ESP_DHCP 1 +#define ESP_DNS 1 +#define ESP_IPV6_AUTOCONFIG 1 +#define ESP_PERF 0 +#define ESP_RANDOM_TCP_PORT 1 +#define ESP_IP4_ATON 1 +#define ESP_LIGHT_SLEEP 1 + +#define TCP_WND_DEFAULT (4*TCP_MSS) +#define TCP_SND_BUF_DEFAULT (2*TCP_MSS) + +#if ESP_PER_SOC_TCP_WND +#define TCP_WND(pcb) (pcb->per_soc_tcp_wnd) +#define TCP_SND_BUF(pcb) (pcb->per_soc_tcp_snd_buf) +#else +#if ESP_PERF +extern unsigned char misc_prof_get_tcpw(void); +extern unsigned char misc_prof_get_tcp_snd_buf(void); +#define TCP_WND(pcb) (misc_prof_get_tcpw()*TCP_MSS) +#define TCP_SND_BUF(pcb) (misc_prof_get_tcp_snd_buf()*TCP_MSS) +#endif +#endif + /** * DHCP_DEBUG: Enable debugging in dhcp.c. */ #define DHCP_DEBUG LWIP_DBG_OFF -#define LWIP_DEBUG 0 +#define LWIP_DEBUG LWIP_DBG_OFF #define TCP_DEBUG LWIP_DBG_OFF -#define THREAD_SAFE_DEBUG LWIP_DBG_OFF -#define LWIP_THREAD_SAFE 1 +#define ESP_THREAD_SAFE_DEBUG LWIP_DBG_OFF #define CHECKSUM_CHECK_UDP 0 #define CHECKSUM_CHECK_IP 0 -#define HEAP_HIGHWAT 20*1024 - #define LWIP_NETCONN_FULLDUPLEX 1 #define LWIP_NETCONN_SEM_PER_THREAD 1 +#define LWIP_DHCP_MAX_NTP_SERVERS CONFIG_LWIP_DHCP_MAX_NTP_SERVERS +#define LWIP_TIMEVAL_PRIVATE 0 +#define SNTP_SET_SYSTEM_TIME_US(sec, us) \ + do { \ + struct timeval tv = { .tv_sec = sec, .tv_usec = us }; \ + settimeofday(&tv, NULL); \ + } while (0); + +#define SNTP_GET_SYSTEM_TIME(sec, us) \ + do { \ + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; \ + gettimeofday(&tv, NULL); \ + (sec) = tv.tv_sec; \ + (us) = tv.tv_usec; \ + } while (0); #define SOC_SEND_LOG //printf diff --git a/components/lwip/include/lwip/port/netif/wlanif.h b/components/lwip/include/lwip/port/netif/wlanif.h index 7eb303eab4..c6f7831b3d 100755 --- a/components/lwip/include/lwip/port/netif/wlanif.h +++ b/components/lwip/include/lwip/port/netif/wlanif.h @@ -8,6 +8,8 @@ #include "esp_wifi.h" +#include "esp_wifi_internal.h" + #include "lwip/err.h" #ifdef __cplusplus @@ -18,8 +20,6 @@ err_t wlanif_init(struct netif *netif); void wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb); -bool ieee80211_output(wifi_interface_t wifi_if, void *buffer, u16_t len); - wifi_interface_t wifi_get_interface(void *dev); void netif_reg_addr_change_cb(void* cb); diff --git a/components/lwip/netif/etharp.c b/components/lwip/netif/etharp.c index 5891c5cfd6..776e949f75 100755 --- a/components/lwip/netif/etharp.c +++ b/components/lwip/netif/etharp.c @@ -55,10 +55,6 @@ #include -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; -#endif - #if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ /** Re-request a used ARP entry 1 minute before it would expire to prevent diff --git a/components/lwip/port/freertos/sys_arch.c b/components/lwip/port/freertos/sys_arch.c index 74a4a996a8..15ba3011d9 100755 --- a/components/lwip/port/freertos/sys_arch.c +++ b/components/lwip/port/freertos/sys_arch.c @@ -56,7 +56,7 @@ sys_mutex_new(sys_mutex_t *pxMutex) xReturn = ERR_OK; } - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mutex_new: m=%p\n", *pxMutex)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: m=%p\n", *pxMutex)); return xReturn; } @@ -89,7 +89,7 @@ sys_mutex_unlock(sys_mutex_t *pxMutex) void sys_mutex_free(sys_mutex_t *pxMutex) { - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mutex_free: m=%p\n", *pxMutex)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_free: m=%p\n", *pxMutex)); vQueueDelete(*pxMutex); } #endif @@ -192,20 +192,20 @@ sys_mbox_new(sys_mbox_t *mbox, int size) { *mbox = malloc(sizeof(struct sys_mbox_s)); if (*mbox == NULL){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("fail to new *mbox\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new *mbox\n")); return ERR_MEM; } (*mbox)->os_mbox = xQueueCreate(size, sizeof(void *)); if ((*mbox)->os_mbox == NULL) { - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("fail to new *mbox->os_mbox\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new *mbox->os_mbox\n")); free(*mbox); return ERR_MEM; } if (sys_mutex_new(&((*mbox)->lock)) != ERR_OK){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("fail to new *mbox->lock\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new *mbox->lock\n")); vQueueDelete((*mbox)->os_mbox); free(*mbox); return ERR_MEM; @@ -213,7 +213,7 @@ sys_mbox_new(sys_mbox_t *mbox, int size) (*mbox)->alive = true; - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("new *mbox ok mbox=%p os_mbox=%p mbox_lock=%p\n", *mbox, (*mbox)->os_mbox, (*mbox)->lock)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("new *mbox ok mbox=%p os_mbox=%p mbox_lock=%p\n", *mbox, (*mbox)->os_mbox, (*mbox)->lock)); return ERR_OK; } @@ -234,7 +234,7 @@ sys_mbox_trypost(sys_mbox_t *mbox, void *msg) if (xQueueSend((*mbox)->os_mbox, &msg, (portTickType)0) == pdPASS) { xReturn = ERR_OK; } else { - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox)); xReturn = ERR_MEM; } @@ -271,7 +271,7 @@ sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) if (*mbox == NULL){ *msg = NULL; - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch: null mbox\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch: null mbox\n")); return -1; } @@ -294,14 +294,14 @@ sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) } else { // block forever for a message. while (1){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch: fetch mbox=%p os_mbox=%p lock=%p\n", mbox, (*mbox)->os_mbox, (*mbox)->lock)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch: fetch mbox=%p os_mbox=%p lock=%p\n", mbox, (*mbox)->os_mbox, (*mbox)->lock)); if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), portMAX_DELAY)){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch:mbox rx msg=%p\n", (*msg))); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch:mbox rx msg=%p\n", (*msg))); break; } if ((*mbox)->alive == false){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch:mbox not alive\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_arch_mbox_fetch:mbox not alive\n")); *msg = NULL; break; } @@ -356,24 +356,24 @@ sys_mbox_free(sys_mbox_t *mbox) uint16_t count = 0; bool post_null = true; - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free: set alive false\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mbox_free: set alive false\n")); (*mbox)->alive = false; while ( count++ < MAX_POLL_CNT ){ //ESP32_WORKAROUND - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free:try lock=%d\n", count)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mbox_free:try lock=%d\n", count)); if (!sys_mutex_trylock( &(*mbox)->lock )){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free:get lock ok %d\n", count)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mbox_free:get lock ok %d\n", count)); sys_mutex_unlock( &(*mbox)->lock ); break; } if (post_null){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free: post null to mbox\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mbox_free: post null to mbox\n")); if (sys_mbox_trypost( mbox, NULL) != ERR_OK){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free: post null mbox fail\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mbox_free: post null mbox fail\n")); } else { post_null = false; - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free: post null mbox ok\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mbox_free: post null mbox ok\n")); } } @@ -383,7 +383,7 @@ sys_mbox_free(sys_mbox_t *mbox) sys_delay_ms(PER_POLL_DELAY); } - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sys_mbox_free:free mbox\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mbox_free:free mbox\n")); if (uxQueueMessagesWaiting((*mbox)->os_mbox)) { xQueueReset((*mbox)->os_mbox); @@ -491,7 +491,7 @@ sys_sem_t* sys_thread_sem_get(void) if (!sem){ sem = sys_thread_sem_init(); } - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sem_get s=%p\n", sem)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem_get s=%p\n", sem)); return sem; } @@ -500,12 +500,12 @@ static void sys_thread_tls_free(int index, void* data) sys_sem_t *sem = (sys_sem_t*)(data); if (sem && *sem){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sem del, i=%d sem=%p\n", index, *sem)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem del, i=%d sem=%p\n", index, *sem)); vSemaphoreDelete(*sem); } if (sem){ - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sem pointer del, i=%d sem_p=%p\n", index, sem)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem pointer del, i=%d sem_p=%p\n", index, sem)); free(sem); } } @@ -526,7 +526,7 @@ sys_sem_t* sys_thread_sem_init(void) return 0; } - LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("sem init sem_p=%p sem=%p cb=%p\n", sem, *sem, sys_thread_tls_free)); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem init sem_p=%p sem=%p cb=%p\n", sem, *sem, sys_thread_tls_free)); vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), SYS_TLS_INDEX, sem, (TlsDeleteCallbackFunction_t)sys_thread_tls_free); return sem; diff --git a/components/lwip/port/netif/wlanif.c b/components/lwip/port/netif/wlanif.c index 9832c41aff..ffad69cd46 100755 --- a/components/lwip/port/netif/wlanif.c +++ b/components/lwip/port/netif/wlanif.c @@ -56,16 +56,8 @@ #define IFNAME0 'e' #define IFNAME1 'n' -#ifdef LWIP_ESP8266 -//TO_DO -//char *hostname; -//bool default_hostname = 1; - static char hostname[16]; -#else -static char hostname[16]; -#endif -#ifdef PERF +#if ESP_PERF uint32_t g_rx_alloc_pbuf_fail_cnt = 0; #endif @@ -95,7 +87,7 @@ low_level_init(struct netif *netif) /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; -#ifdef LWIP_ESP8266 +#if ESP_LWIP #if LWIP_IGMP @@ -133,7 +125,7 @@ low_level_output(struct netif *netif, struct pbuf *p) return ERR_IF; } -#ifdef LWIP_ESP8266 +#if ESP_LWIP q = p; u16_t pbuf_x_len = 0; pbuf_x_len = q->len; @@ -150,16 +142,13 @@ low_level_output(struct netif *netif, struct pbuf *p) } } - ieee80211_output(wifi_if, q->payload, pbuf_x_len); - return ERR_OK; - + return esp_wifi_internal_tx(wifi_if, q->payload, pbuf_x_len); #else for(q = p; q != NULL; q = q->next) { - ieee80211_output(wifi_if, q->payload, q->len); + esp_wifi_internal_tx(wifi_if, q->payload, q->len); } -#endif - return ERR_OK; +#endif } /** @@ -172,7 +161,7 @@ low_level_output(struct netif *netif, struct pbuf *p) * @param netif the lwip network interface structure for this ethernetif */ void -#ifdef LWIP_ESP8266 +#if ESP_LWIP wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) #else wlanif_input(struct netif *netif, void *buffer, uint16 len) @@ -180,17 +169,17 @@ wlanif_input(struct netif *netif, void *buffer, uint16 len) { struct pbuf *p; -#ifdef LWIP_ESP8266 +#if ESP_LWIP if(buffer== NULL) goto _exit; if(netif == NULL) goto _exit; #endif -#ifdef LWIP_ESP8266 +#if ESP_LWIP p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); if (p == NULL){ -#ifdef PERF +#if ESP_PERF g_rx_alloc_pbuf_fail_cnt++; #endif return; @@ -236,7 +225,7 @@ wlanif_init(struct netif *netif) #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ -#ifdef LWIP_ESP8266 +#if ESP_LWIP //TO_DO /* if ((struct netif *)wifi_get_netif(STATION_IF) == netif) { diff --git a/components/mbedtls/component.mk b/components/mbedtls/component.mk index 98838d4d7b..bd7209a926 100644 --- a/components/mbedtls/component.mk +++ b/components/mbedtls/component.mk @@ -6,4 +6,3 @@ COMPONENT_ADD_INCLUDEDIRS := port/include include COMPONENT_SRCDIRS := library port -include $(IDF_PATH)/make/component_common.mk diff --git a/components/micro-ecc/component.mk b/components/micro-ecc/component.mk new file mode 100644 index 0000000000..df73f7a3b2 --- /dev/null +++ b/components/micro-ecc/component.mk @@ -0,0 +1,6 @@ +# only compile the micro-ecc/uECC.c source file +# (SRCDIRS is needed so build system can find the source file) +COMPONENT_SRCDIRS := micro-ecc +COMPONENT_OBJS := micro-ecc/uECC.o + +COMPONENT_ADD_INCLUDEDIRS := micro-ecc diff --git a/components/micro-ecc/micro-ecc b/components/micro-ecc/micro-ecc new file mode 160000 index 0000000000..14222e062d --- /dev/null +++ b/components/micro-ecc/micro-ecc @@ -0,0 +1 @@ +Subproject commit 14222e062d77f45321676e813d9525f32a88e8fa diff --git a/components/newlib/component.mk b/components/newlib/component.mk index 7c8c74debe..4f567242b6 100644 --- a/components/newlib/component.mk +++ b/components/newlib/component.mk @@ -1,8 +1,4 @@ -COMPONENT_ADD_LDFLAGS := $(abspath lib/libc.a) $(abspath lib/libm.a) +COMPONENT_ADD_LDFLAGS := $(COMPONENT_PATH)/lib/libc.a $(COMPONENT_PATH)/lib/libm.a -lnewlib +COMPONENT_ADD_INCLUDEDIRS := include platform_include -define COMPONENT_BUILDRECIPE - #Nothing to do; this does not generate a library. -endef - -include $(IDF_PATH)/make/component_common.mk diff --git a/components/esp32/syscalls.c b/components/newlib/locks.c similarity index 54% rename from components/esp32/syscalls.c rename to components/newlib/locks.c index 052605ee3e..21b974a1f1 100644 --- a/components/esp32/syscalls.c +++ b/components/newlib/locks.c @@ -3,7 +3,7 @@ // 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 @@ -11,181 +11,17 @@ // 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 -#include -#include -#include -#include -#include -#include + +#include #include +#include #include "esp_attr.h" -#include "rom/libc_stubs.h" -#include "rom/uart.h" #include "soc/cpu.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/portmacro.h" #include "freertos/task.h" -void abort() { - do - { - __asm__ ("break 0,0"); - *((int*) 0) = 0; - } while(true); -} - -void* _malloc_r(struct _reent *r, size_t size) { - return pvPortMalloc(size); -} - -void _free_r(struct _reent *r, void* ptr) { - return vPortFree(ptr); -} - -void* _realloc_r(struct _reent *r, void* ptr, size_t size) { - void* new_chunk; - if (size == 0) { - if (ptr) { - vPortFree(ptr); - } - return NULL; - } - - new_chunk = pvPortMalloc(size); - if (new_chunk && ptr) { - memcpy(new_chunk, ptr, size); - vPortFree(ptr); - } - // realloc behaviour: don't free original chunk if alloc failed - return new_chunk; -} - -void* _calloc_r(struct _reent *r, size_t count, size_t size) { - void* result = pvPortMalloc(count * size); - if (result) - { - memset(result, 0, count * size); - } - return result; -} - -int _system_r(struct _reent *r, const char *str) { - abort(); - return 0; -} - -int _rename_r(struct _reent *r, const char *src, const char *dst) { - abort(); - return 0; -} - -clock_t _times_r(struct _reent *r, struct tms *ptms) { - abort(); - return 0; -} - -// TODO: read time from RTC -int _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz) { - abort(); - return 0; -} - -void _raise_r(struct _reent *r) { - abort(); -} - -int _unlink_r(struct _reent *r, const char *path) { - abort(); - return 0; -} - -int _link_r(struct _reent *r, const char* n1, const char* n2) { - abort(); - return 0; -} - -int _stat_r(struct _reent *r, const char * path, struct stat * st) { - return 0; -} - -int _fstat_r(struct _reent *r, int fd, struct stat * st) { - st->st_mode = S_IFCHR; - return 0; -} - -void* _sbrk_r(struct _reent *r, ptrdiff_t sz) { - abort(); - return 0; -} - -int _getpid_r(struct _reent *r) { - abort(); - return 0; -} - -int _kill_r(struct _reent *r, int pid, int sig) { - abort(); - return 0; -} - -void _exit_r(struct _reent *r, int e) { - abort(); -} - -int _close_r(struct _reent *r, int fd) { - return 0; -} - -int _open_r(struct _reent *r, const char * path, int flags, int mode) { - return 0; -} - -void _exit(int __status) { - abort(); -} - -ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) { - const char *data_c = (const char *)data; - if (fd == STDOUT_FILENO) { - static _lock_t stdout_lock; /* lazily initialised */ - /* Even though newlib does stream locking on stdout, we need - a dedicated stdout UART lock... - - This is because each task has its own _reent structure with - unique FILEs for stdin/stdout/stderr, so these are - per-thread (lazily initialised by __sinit the first time a - stdio function is used, see findfp.c:235. - - It seems like overkill to allocate a FILE-per-task and lock - a thread-local stream, but I see no easy way to fix this - (pre-__sinit_, tasks have "fake" FILEs ie __sf_fake_stdout - which aren't fully valid.) - */ - _lock_acquire_recursive(&stdout_lock); - for (size_t i = 0; i < size; i++) { -#if CONFIG_NEWLIB_STDOUT_ADDCR - if (data_c[i]=='\n') { - uart_tx_one_char('\r'); - } -#endif - uart_tx_one_char(data_c[i]); - } - _lock_release_recursive(&stdout_lock); - } - return size; -} - -_off_t _lseek_r(struct _reent *r, int fd, _off_t size, int mode) { - return 0; -} - -// TODO: implement reading from UART -ssize_t _read_r(struct _reent *r, int fd, void * dst, size_t size) { - return 0; -} - /* Notes on our newlib lock implementation: * * - Use FreeRTOS mutex semaphores as locks. @@ -369,89 +205,3 @@ void IRAM_ATTR _lock_release(_lock_t *lock) { void IRAM_ATTR _lock_release_recursive(_lock_t *lock) { lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX); } - -// This function is not part on newlib API, it is defined in libc/stdio/local.h -// It is called as part of _reclaim_reent via a pointer in __cleanup member -// of struct _reent. -// This function doesn't call _fclose_r for _stdin, _stdout, _stderr members -// of struct reent. Not doing so causes a memory leak each time a task is -// terminated. We replace __cleanup member with _extra_cleanup_r (below) to work -// around this. -extern void _cleanup_r(struct _reent* r); - -void _extra_cleanup_r(struct _reent* r) -{ - _cleanup_r(r); - _fclose_r(r, r->_stdout); - _fclose_r(r, r->_stderr); - _fclose_r(r, r->_stdin); -} - -static struct _reent s_reent; - -/* - General ToDo that the Xtensa newlib support code did but we do not: Close every open fd a running task had when the task - is killed. Do we want that too? - JD -*/ - -extern int _printf_float(struct _reent *rptr, - void *pdata, - FILE * fp, - int (*pfunc) (struct _reent *, FILE *, _CONST char *, size_t len), - va_list * ap); - - -extern int _scanf_float(struct _reent *rptr, - void *pdata, - FILE *fp, - va_list *ap); - - -static struct syscall_stub_table s_stub_table = { - .__getreent = &__getreent, - ._malloc_r = &_malloc_r, - ._free_r = &_free_r, - ._realloc_r = &_realloc_r, - ._calloc_r = &_calloc_r, - ._abort = &abort, - ._system_r = &_system_r, - ._rename_r = &_rename_r, - ._times_r = &_times_r, - ._gettimeofday_r = &_gettimeofday_r, - ._raise_r = &_raise_r, - ._unlink_r = &_unlink_r, - ._link_r = &_link_r, - ._stat_r = &_stat_r, - ._fstat_r = &_fstat_r, - ._sbrk_r = &_sbrk_r, - ._getpid_r = &_getpid_r, - ._kill_r = &_kill_r, - ._exit_r = &_exit_r, - ._close_r = &_close_r, - ._open_r = &_open_r, - ._write_r = (int (*)(struct _reent *r, int, const void *, int)) &_write_r, - ._lseek_r = (int (*)(struct _reent *r, int, int, int)) &_lseek_r, - ._read_r = (int (*)(struct _reent *r, int, void *, int)) &_read_r, - ._lock_init = &_lock_init, - ._lock_init_recursive = &_lock_init_recursive, - ._lock_close = &_lock_close, - ._lock_close_recursive = &_lock_close, - ._lock_acquire = &_lock_acquire, - ._lock_acquire_recursive = &_lock_acquire_recursive, - ._lock_try_acquire = &_lock_try_acquire, - ._lock_try_acquire_recursive = &_lock_try_acquire_recursive, - ._lock_release = &_lock_release, - ._lock_release_recursive = &_lock_release_recursive, - ._printf_float = &_printf_float, - ._scanf_float = &_scanf_float, -}; - -void ets_setup_syscalls() { - syscall_table_ptr_pro = &s_stub_table; - syscall_table_ptr_app = &s_stub_table; - _GLOBAL_REENT = &s_reent; - environ = malloc(sizeof(char*)); - environ[0] = NULL; -} - - diff --git a/components/newlib/platform_include/esp_newlib.h b/components/newlib/platform_include/esp_newlib.h new file mode 100644 index 0000000000..eac3544259 --- /dev/null +++ b/components/newlib/platform_include/esp_newlib.h @@ -0,0 +1,43 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP_NEWLIB_H__ +#define __ESP_NEWLIB_H__ + +#include + +/** + * Replacement for newlib's _REENT_INIT_PTR and __sinit. + * + * Called from startup code and FreeRTOS, not intended to be called from + * application code. + */ +void esp_reent_init(struct _reent* r); + +/** + * Function which sets up syscall table used by newlib functions in ROM. + * + * Called from the startup code, not intended to be called from application + * code. + */ +void esp_setup_syscall_table(); + +/** + * Initialize hardware timer used as time source for newlib time functions. + * + * Called from the startup code, not intended to be called from application. + */ +void esp_setup_time_syscalls(); + +#endif //__ESP_NEWLIB_H__ diff --git a/components/newlib/reent_init.c b/components/newlib/reent_init.c new file mode 100644 index 0000000000..5c29e898c6 --- /dev/null +++ b/components/newlib/reent_init.c @@ -0,0 +1,45 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include "esp_attr.h" + +/* This function is not part on newlib API, it is defined in libc/stdio/local.h + * There is no nice way to get __cleanup member populated while avoiding __sinit, + * so extern declaration is used here. + */ +extern void _cleanup_r(struct _reent* r); + +/** + * This is the replacement for newlib's _REENT_INIT_PTR and __sinit. + * The problem with __sinit is that it allocates three FILE structures + * (stdin, stdout, stderr). Having individual standard streams for each task + * is a bit too much on a small embedded system. So we point streams + * to the streams of the global struct _reent, which are initialized in + * startup code. + */ +void IRAM_ATTR esp_reent_init(struct _reent* r) +{ + memset(r, 0, sizeof(*r)); + r->_stdout = _GLOBAL_REENT->_stdout; + r->_stderr = _GLOBAL_REENT->_stderr; + r->_stdin = _GLOBAL_REENT->_stdin; + r->__cleanup = &_cleanup_r; + r->__sdidinit = 1; + r->__sglue._next = NULL; + r->__sglue._niobs = 0; + r->__sglue._iobs = NULL; + r->_current_locale = "C"; +} diff --git a/components/newlib/syscall_table.c b/components/newlib/syscall_table.c new file mode 100644 index 0000000000..feed768172 --- /dev/null +++ b/components/newlib/syscall_table.c @@ -0,0 +1,92 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rom/libc_stubs.h" +#include "esp_vfs.h" +#include "esp_newlib.h" + +static struct _reent s_reent; + +extern int _printf_float(struct _reent *rptr, + void *pdata, + FILE * fp, + int (*pfunc) (struct _reent *, FILE *, _CONST char *, size_t len), + va_list * ap); + + +extern int _scanf_float(struct _reent *rptr, + void *pdata, + FILE *fp, + va_list *ap); + + +static struct syscall_stub_table s_stub_table = { + .__getreent = &__getreent, + ._malloc_r = &_malloc_r, + ._free_r = &_free_r, + ._realloc_r = &_realloc_r, + ._calloc_r = &_calloc_r, + ._abort = &abort, + ._system_r = &_system_r, + ._rename_r = &esp_vfs_rename, + ._times_r = &_times_r, + ._gettimeofday_r = &_gettimeofday_r, + ._raise_r = (void (*)(struct _reent *r)) &_raise_r, + ._unlink_r = &esp_vfs_unlink, + ._link_r = &esp_vfs_link, + ._stat_r = &esp_vfs_stat, + ._fstat_r = &esp_vfs_fstat, + ._sbrk_r = &_sbrk_r, + ._getpid_r = &_getpid_r, + ._kill_r = &_kill_r, + ._exit_r = NULL, // never called in ROM + ._close_r = &esp_vfs_close, + ._open_r = &esp_vfs_open, + ._write_r = (int (*)(struct _reent *r, int, const void *, int)) &esp_vfs_write, + ._lseek_r = (int (*)(struct _reent *r, int, int, int)) &esp_vfs_lseek, + ._read_r = (int (*)(struct _reent *r, int, void *, int)) &esp_vfs_read, + ._lock_init = &_lock_init, + ._lock_init_recursive = &_lock_init_recursive, + ._lock_close = &_lock_close, + ._lock_close_recursive = &_lock_close, + ._lock_acquire = &_lock_acquire, + ._lock_acquire_recursive = &_lock_acquire_recursive, + ._lock_try_acquire = &_lock_try_acquire, + ._lock_try_acquire_recursive = &_lock_try_acquire_recursive, + ._lock_release = &_lock_release, + ._lock_release_recursive = &_lock_release_recursive, + ._printf_float = &_printf_float, + ._scanf_float = &_scanf_float, +}; + +void esp_setup_syscall_table() +{ + syscall_table_ptr_pro = &s_stub_table; + syscall_table_ptr_app = &s_stub_table; + _GLOBAL_REENT = &s_reent; + environ = malloc(sizeof(char*)); + environ[0] = NULL; +} + + diff --git a/components/newlib/syscalls.c b/components/newlib/syscalls.c new file mode 100644 index 0000000000..3b2fbf62ca --- /dev/null +++ b/components/newlib/syscalls.c @@ -0,0 +1,105 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include +#include +#include +#include +#include "esp_attr.h" +#include "freertos/FreeRTOS.h" + +void IRAM_ATTR abort() +{ + do + { + __asm__ ("break 0,0"); + *((int*) 0) = 0; + } while(true); +} + +void* IRAM_ATTR _malloc_r(struct _reent *r, size_t size) +{ + return pvPortMalloc(size); +} + +void IRAM_ATTR _free_r(struct _reent *r, void* ptr) +{ + vPortFree(ptr); +} + +void* IRAM_ATTR _realloc_r(struct _reent *r, void* ptr, size_t size) +{ + void* new_chunk; + if (size == 0) { + if (ptr) { + vPortFree(ptr); + } + return NULL; + } + + new_chunk = pvPortMalloc(size); + if (new_chunk && ptr) { + memcpy(new_chunk, ptr, size); + vPortFree(ptr); + } + // realloc behaviour: don't free original chunk if alloc failed + return new_chunk; +} + +void* IRAM_ATTR _calloc_r(struct _reent *r, size_t count, size_t size) +{ + void* result = pvPortMalloc(count * size); + if (result) + { + memset(result, 0, count * size); + } + return result; +} + +int _system_r(struct _reent *r, const char *str) +{ + __errno_r(r) = ENOSYS; + return -1; +} + +void _raise_r(struct _reent *r) +{ + abort(); +} + +void* _sbrk_r(struct _reent *r, ptrdiff_t sz) +{ + abort(); +} + +int _getpid_r(struct _reent *r) +{ + __errno_r(r) = ENOSYS; + return -1; +} + +int _kill_r(struct _reent *r, int pid, int sig) +{ + __errno_r(r) = ENOSYS; + return -1; +} + +void _exit(int __status) +{ + abort(); +} + diff --git a/components/newlib/time.c b/components/newlib/time.c new file mode 100644 index 0000000000..3426a01bfb --- /dev/null +++ b/components/newlib/time.c @@ -0,0 +1,186 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "esp_attr.h" +#include "soc/soc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/frc_timer_reg.h" +#include "rom/ets_sys.h" +#include "freertos/FreeRTOS.h" +#include "freertos/xtensa_api.h" +#include "freertos/task.h" +#include "sdkconfig.h" + +#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 ) +#define WITH_RTC 1 +#endif + +#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 ) +#define WITH_FRC1 1 +#endif + +#ifdef WITH_RTC +static uint64_t get_rtc_time_us() +{ + SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_M); + while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID_M) == 0) { + ; + } + CLEAR_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_M); + uint64_t low = READ_PERI_REG(RTC_CNTL_TIME0_REG); + uint64_t high = READ_PERI_REG(RTC_CNTL_TIME1_REG); + uint64_t ticks = (high << 32) | low; + return ticks * 100 / (RTC_CTNL_SLOWCLK_FREQ / 10000); // scale RTC_CTNL_SLOWCLK_FREQ to avoid overflow +} +#endif // WITH_RTC + + +// s_boot_time: time from Epoch to the first boot time +#ifdef WITH_RTC +static RTC_DATA_ATTR struct timeval s_boot_time; +#elif defined(WITH_FRC1) +static struct timeval s_boot_time; +#endif + +#if defined(WITH_RTC) || defined(WITH_FRC1) +static _lock_t s_boot_time_lock; +#endif + +#ifdef WITH_FRC1 +#define FRC1_PRESCALER 16 +#define FRC1_PRESCALER_CTL 2 +#define FRC1_TICK_FREQ (APB_CLK_FREQ / FRC1_PRESCALER) +#define FRC1_TICKS_PER_US (FRC1_TICK_FREQ / 1000000) +#define FRC1_ISR_PERIOD_US (FRC_TIMER_LOAD_VALUE(0) / FRC1_TICKS_PER_US) +// Counter frequency will be APB_CLK_FREQ / 16 = 5 MHz +// 1 tick = 0.2 us +// Timer has 23 bit counter, so interrupt will fire each 1677721.6 microseconds. +// This is not a whole number, so timer will drift by 0.3 ppm due to rounding error. + +static volatile uint64_t s_microseconds = 0; + +static void IRAM_ATTR frc_timer_isr() +{ + WRITE_PERI_REG(FRC_TIMER_INT_REG(0), FRC_TIMER_INT_CLR); + s_microseconds += FRC1_ISR_PERIOD_US; +} + +#endif // WITH_FRC1 + +void esp_setup_time_syscalls() +{ +#if defined( WITH_FRC1 ) +#if defined( WITH_RTC ) + // initialize time from RTC clock + s_microseconds = get_rtc_time_us(); +#endif //WITH_RTC + + // set up timer + WRITE_PERI_REG(FRC_TIMER_CTRL_REG(0), \ + FRC_TIMER_AUTOLOAD | \ + (FRC1_PRESCALER_CTL << FRC_TIMER_PRESCALER_S) | \ + FRC_TIMER_EDGE_INT); + + WRITE_PERI_REG(FRC_TIMER_LOAD_REG(0), FRC_TIMER_LOAD_VALUE(0)); + SET_PERI_REG_MASK(FRC_TIMER_CTRL_REG(0), + FRC_TIMER_ENABLE | \ + FRC_TIMER_INT_ENABLE); + intr_matrix_set(xPortGetCoreID(), ETS_TIMER1_INTR_SOURCE, ETS_FRC1_INUM); + xt_set_interrupt_handler(ETS_FRC1_INUM, &frc_timer_isr, NULL); + xt_ints_on(1 << ETS_FRC1_INUM); +#endif // WITH_FRC1 +} + +clock_t IRAM_ATTR _times_r(struct _reent *r, struct tms *ptms) +{ + clock_t t = xTaskGetTickCount() * (portTICK_PERIOD_MS * CLK_TCK / 1000); + ptms->tms_cstime = 0; + ptms->tms_cutime = 0; + ptms->tms_stime = t; + ptms->tms_utime = 0; + struct timeval tv = {0, 0}; + _gettimeofday_r(r, &tv, NULL); + return (clock_t) tv.tv_sec; +} + +#if defined( WITH_FRC1 ) || defined( WITH_RTC ) +static uint64_t get_time_since_boot() +{ + uint64_t microseconds = 0; +#ifdef WITH_FRC1 + uint32_t timer_ticks_before = READ_PERI_REG(FRC_TIMER_COUNT_REG(0)); + microseconds = s_microseconds; + uint32_t timer_ticks_after = READ_PERI_REG(FRC_TIMER_COUNT_REG(0)); + if (timer_ticks_after > timer_ticks_before) { + // overflow happened at some point between getting + // timer_ticks_before and timer_ticks_after + // microseconds value is ambiguous, get a new one + microseconds = s_microseconds; + } + microseconds += (FRC_TIMER_LOAD_VALUE(0) - timer_ticks_after) / FRC1_TICKS_PER_US; +#elif defined(WITH_RTC) + microseconds = get_rtc_time_us(); +#endif + return microseconds; +} +#endif // defined( WITH_FRC1 ) || defined( WITH_RTC ) + +int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz) +{ + (void) tz; +#if defined( WITH_FRC1 ) || defined( WITH_RTC ) + uint64_t microseconds = get_time_since_boot(); + if (tv) { + _lock_acquire(&s_boot_time_lock); + microseconds += s_boot_time.tv_usec; + tv->tv_sec = s_boot_time.tv_sec + microseconds / 1000000; + tv->tv_usec = microseconds % 1000000; + _lock_release(&s_boot_time_lock); + } + return 0; +#else + __errno_r(r) = ENOSYS; + return -1; +#endif // defined( WITH_FRC1 ) || defined( WITH_RTC ) +} + +int settimeofday(const struct timeval *tv, const struct timezone *tz) +{ + (void) tz; +#if defined( WITH_FRC1 ) || defined( WITH_RTC ) + if (tv) { + _lock_acquire(&s_boot_time_lock); + uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec; + uint64_t since_boot = get_time_since_boot(); + uint64_t boot_time = now - since_boot; + + s_boot_time.tv_sec = boot_time / 1000000; + s_boot_time.tv_usec = boot_time % 1000000; + _lock_release(&s_boot_time_lock); + } + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} diff --git a/components/nghttp/component.mk b/components/nghttp/component.mk index a4dca5cf70..d2cd0455f5 100644 --- a/components/nghttp/component.mk +++ b/components/nghttp/component.mk @@ -5,5 +5,3 @@ COMPONENT_ADD_INCLUDEDIRS := port/include include COMPONENT_SRCDIRS := library port - -include $(IDF_PATH)/make/component_common.mk \ No newline at end of file diff --git a/components/nghttp/library/nghttp2_session.c b/components/nghttp/library/nghttp2_session.c index f93cd1729b..0100dd32c4 100644 --- a/components/nghttp/library/nghttp2_session.c +++ b/components/nghttp/library/nghttp2_session.c @@ -7177,7 +7177,7 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session, return session->remote_settings.max_header_list_size; } - assert(0); + abort(); } static int nghttp2_session_upgrade_internal(nghttp2_session *session, diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst index 2f1c469135..ade5518aa5 100644 --- a/components/nvs_flash/README.rst +++ b/components/nvs_flash/README.rst @@ -7,14 +7,14 @@ Introduction Non-volatile storage (NVS) library is designed to store key-value pairs in flash. This sections introduces some concepts used by NVS. Underlying storage -~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^ Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The range of flash sectors to be used by the library is provided to ``nvs_flash_init`` function. Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. Keys and values -~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^ NVS operates on key-value pairs. Keys are ASCII strings, maximum key length is currently 15 characters. Values can have one of the following types: @@ -32,12 +32,12 @@ Keys are required to be unique. Writing a value for a key which already exists b Data type check is also performed when reading a value. An error is returned if data type of read operation doesn’t match the data type of the value. Namespaces -~~~~~~~~~~ +^^^^^^^^^^ To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e. 15 character maximum length. Namespace name is specified in the ``nvs_open`` call. This call returns an opaque handle, which is used in subsequent calls to ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, handle is associated with a namespace, and key names will not collide with same names in other namespaces. Security, tampering, and robustness -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NVS library doesn't implement tamper prevention measures. It is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. @@ -59,12 +59,12 @@ Internals --------- Log of key-value pairs -~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^ NVS stores key-value pairs sequentially, with new key-value pairs being added at the end. When a value of any given key has to be updated, new key-value pair is added at the end of the log and old key-value pair is marked as erased. Pages and entries -~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^ NVS library uses two main entities in its operation: pages and entries. Page is a logical structure which stores a portion of the overall log. Logical page corresponds to one physical sector of flash memory. Pages which are in use have a *sequence number* associated with them. Sequence numbers impose an ordering on pages. Higher sequence numbers correspond to pages which were created later. Each page can be in one of the following states: @@ -101,7 +101,7 @@ Mapping from flash sectors to logical pages doesn't have any particular order. L +----------+ +----------+ +----------+ +----------+ Structure of a page -~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^ For now we assume that flash sector size is 4096 bytes and that ESP32 flash encryption hardware operates on 32-byte blocks. It is possible to introduce some settings configurable at compile-time (e.g. via menuconfig) to accommodate flash chips with different sector sizes (although it is not clear if other components in the system, e.g. SPI flash driver and SPI flash cache can support these other sizes). @@ -133,7 +133,7 @@ CRC32 value in header is calculated over the part which doesn't include state va The following sections describe structure of entry state bitmap and entry itself. Entry and entry state bitmap -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Each entry can be in one of the following three states. Each state is represented with two bits in the entry state bitmap. Final four bits in the bitmap (256 - 2 * 126) are unused. @@ -148,7 +148,7 @@ Erased (2'b00) Structure of entry -~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^ For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. In case when a key-value pair spans multiple entries, all entries are stored in the same page. @@ -200,7 +200,7 @@ Variable length values (strings and blobs) are written into subsequent entries, Namespaces -~~~~~~~~~~ +^^^^^^^^^^ As mentioned above, each key-value pair belongs to one of the namespaces. Namespaces identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces. @@ -218,10 +218,9 @@ As mentioned above, each key-value pair belongs to one of the namespaces. Namesp Item hash list -~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^ To reduce the number of reads performed from flash memory, each member of Page class maintains a list of pairs: (item index; item hash). This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, ``Page::findItem`` first performs search for item hash in the hash list. This gives the item index within the page, if such an item exists. Due to a hash collision it is possible that a different item will be found. This is handled by falling back to iteration over items in flash. Each node in hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace and key name. CRC32 is used for calculation, result is truncated to 24 bits. To reduce overhead of storing 32-bit entries in a linked list, list is implemented as a doubly-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and 32-bit count field. Minimal amount of extra RAM useage per page is therefore 128 bytes, maximum is 640 bytes. - diff --git a/components/nvs_flash/component.mk b/components/nvs_flash/component.mk index 02ff8cf038..a905ca689e 100755 --- a/components/nvs_flash/component.mk +++ b/components/nvs_flash/component.mk @@ -6,4 +6,3 @@ COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_SRCDIRS := src -include $(IDF_PATH)/make/component_common.mk diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index 912ea22103..8418959793 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -28,23 +28,27 @@ extern "C" { */ typedef uint32_t nvs_handle; -#define ESP_ERR_NVS_BASE 0x1100 -#define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) -#define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) -#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) -#define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) -#define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) -#define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) -#define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) -#define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) -#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) -#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) -#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) -#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) +#define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */ +#define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) /*!< The storage driver is not initialized */ +#define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) /*!< Id namespace doesn’t exist yet and mode is NVS_READONLY */ +#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< TBA */ +#define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) /*!< Storage handle was opened as read only */ +#define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) /*!< There is not enough space in the underlying storage to save the value */ +#define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) /*!< Namespace name doesn’t satisfy constraints */ +#define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) /*!< Handle has been closed or is NULL */ +#define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) /*!< The value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again. */ +#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< TBA */ +#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< TBA */ +#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< TBA */ +#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< TBA */ +/** + * @brief Mode of opening the non-volatile storage + * + */ typedef enum { - NVS_READONLY, - NVS_READWRITE + NVS_READONLY, /*!< Read only */ + NVS_READWRITE /*!< Read and write */ } nvs_open_mode; /** @@ -58,12 +62,13 @@ typedef enum { * underlying implementation, but is guaranteed to be * at least 16 characters. Shouldn't be empty. * @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will - * open a handle for reading only. All write requests will - * be rejected for this handle. + * open a handle for reading only. All write requests will + * be rejected for this handle. * @param[out] out_handle If successful (return code is zero), handle will be * returned in this argument. * - * @return - ESP_OK if storage handle was opened successfully + * @return + * - ESP_OK if storage handle was opened successfully * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized * - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and * mode is NVS_READONLY @@ -86,7 +91,8 @@ esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_ha * @param[in] value The value to set. * @param[in] length For nvs_set_blob: length of binary value to set, in bytes. * - * @return - ESP_OK if value was set successfully + * @return + * - ESP_OK if value was set successfully * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints @@ -129,24 +135,26 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * It is suggested that nvs_get/set_str is used for zero-terminated C strings, and * nvs_get/set_blob used for arbitrary data structures. * - * Example of using nvs_get_i32: + * \code{c} + * // Example of using nvs_get_i32: * int32_t max_buffer_size = 4096; // default value * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size); * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND); * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still * // have its default value. * - * Example (without error checking) of using nvs_get_str to get a string into dynamic array: + * // Example (without error checking) of using nvs_get_str to get a string into dynamic array: * size_t required_size; * nvs_get_str(my_handle, "server_name", NULL, &required_size); * char* server_name = malloc(required_size); * nvs_get_str(my_handle, "server_name", server_name, &required_size); * - * Example (without error checking) of using nvs_get_blob to get a binary data + * // Example (without error checking) of using nvs_get_blob to get a binary data * into a static array: * uint8_t mac_addr[6]; * size_t size = sizeof(mac_addr); * nvs_get_blob(my_handle, "dst_mac_addr", mac_addr, &size); + * \endcode * * @param[in] handle Handle obtained from nvs_open function. * @param[in] key Key name. Maximal length is determined by the underlying @@ -162,7 +170,8 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * zero, will be set to the actual length of the value * written. For nvs_get_str this includes zero terminator. * - * @return - ESP_OK if the value was retrieved successfully + * @return + * - ESP_OK if the value was retrieved successfully * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints @@ -191,7 +200,8 @@ esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size * implementation, but is guaranteed to be at least * 16 characters. Shouldn't be empty. * - * @return - ESP_OK if erase operation was successful + * @return + * - ESP_OK if erase operation was successful * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist @@ -207,7 +217,8 @@ esp_err_t nvs_erase_key(nvs_handle handle, const char* key); * @param[in] handle Storage handle obtained with nvs_open. * Handles that were opened read only cannot be used. * - * @return - ESP_OK if erase operation was successful + * @return + * - ESP_OK if erase operation was successful * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only * - other error codes from the underlying storage driver @@ -224,7 +235,8 @@ esp_err_t nvs_erase_all(nvs_handle handle); * @param[in] handle Storage handle obtained with nvs_open. * Handles that were opened read only cannot be used. * - * @return - ESP_OK if the changes have been written successfully + * @return + * - ESP_OK if the changes have been written successfully * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - other error codes from the underlying storage driver */ @@ -249,3 +261,4 @@ void nvs_close(nvs_handle handle); #endif #endif //ESP_NVS_H + diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index ce98f39407..1cade0e956 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -22,6 +22,8 @@ extern "C" { Temporarily, this region is hardcoded as a 12KB (0x3000 byte) region starting at 24KB (0x6000 byte) offset in flash. + + @return ESP_OK if flash was successfully initialised. */ esp_err_t nvs_flash_init(void); diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index 0a56925c0c..c1a910260e 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -116,6 +116,7 @@ extern "C" void nvs_close(nvs_handle handle) return; } s_nvs_handles.erase(it); + delete static_cast(it); } extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key) diff --git a/components/nvs_flash/src/nvs_item_hash_list.cpp b/components/nvs_flash/src/nvs_item_hash_list.cpp index 7fa019dffe..cf48477d61 100644 --- a/components/nvs_flash/src/nvs_item_hash_list.cpp +++ b/components/nvs_flash/src/nvs_item_hash_list.cpp @@ -17,7 +17,11 @@ namespace nvs { -HashList::~HashList() +HashList::HashList() +{ +} + +void HashList::clear() { for (auto it = mBlockList.begin(); it != mBlockList.end();) { auto tmp = it; @@ -26,6 +30,11 @@ HashList::~HashList() delete static_cast(tmp); } } + +HashList::~HashList() +{ + clear(); +} HashList::HashListBlock::HashListBlock() { diff --git a/components/nvs_flash/src/nvs_item_hash_list.hpp b/components/nvs_flash/src/nvs_item_hash_list.hpp index b40a53d615..3f8dcc850a 100644 --- a/components/nvs_flash/src/nvs_item_hash_list.hpp +++ b/components/nvs_flash/src/nvs_item_hash_list.hpp @@ -25,11 +25,18 @@ namespace nvs class HashList { public: + HashList(); ~HashList(); + void insert(const Item& item, size_t index); void erase(const size_t index); size_t find(size_t start, const Item& item); - + void clear(); + +private: + HashList(const HashList& other); + const HashList& operator= (const HashList& rhs); + protected: struct HashListNode { @@ -57,7 +64,6 @@ protected: HashListNode mNodes[ENTRY_COUNT]; }; - typedef intrusive_list TBlockList; TBlockList mBlockList; }; // class HashList diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index 4f6a198c61..d2ca225352 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -3,7 +3,7 @@ // 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 @@ -37,7 +37,7 @@ esp_err_t Page::load(uint32_t sectorNumber) mErasedEntryCount = 0; Header header; - auto rc = spi_flash_read(mBaseAddress, reinterpret_cast(&header), sizeof(header)); + auto rc = spi_flash_read(mBaseAddress, &header, sizeof(header)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -86,7 +86,7 @@ esp_err_t Page::load(uint32_t sectorNumber) esp_err_t Page::writeEntry(const Item& item) { - auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), reinterpret_cast(&item), sizeof(item)); + auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), &item, sizeof(item)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -114,7 +114,7 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size) assert(mFirstUsedEntry != INVALID_ENTRY); const uint16_t count = size / ENTRY_SIZE; - auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), reinterpret_cast(data), static_cast(size)); + auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), data, size); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -131,8 +131,12 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size) esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize) { Item item; - esp_err_t err; + + if (mState == PageState::INVALID) { + return ESP_ERR_NVS_INVALID_STATE; + } + if (mState == PageState::UNINITIALIZED) { err = initialize(); if (err != ESP_OK) { @@ -166,7 +170,6 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c } // write first item - size_t span = (totalSize + ENTRY_SIZE - 1) / ENTRY_SIZE; item = Item(nsIndex, datatype, span, key); mHashList.insert(item, mNextFreeEntry); @@ -215,6 +218,11 @@ esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, vo { size_t index = 0; Item item; + + if (mState == PageState::INVALID) { + return ESP_ERR_NVS_INVALID_STATE; + } + esp_err_t rc = findItem(nsIndex, datatype, key, index, item); if (rc != ESP_OK) { return rc; @@ -293,6 +301,8 @@ esp_err_t Page::eraseEntryAndSpan(size_t index) } if (item.calculateCrc32() != item.crc32) { rc = alterEntryState(index, EntryState::ERASED); + --mUsedEntryCount; + ++mErasedEntryCount; if (rc != ESP_OK) { return rc; } @@ -397,7 +407,7 @@ esp_err_t Page::mLoadEntryTable() mState == PageState::FULL || mState == PageState::FREEING) { auto rc = spi_flash_read(mBaseAddress + ENTRY_TABLE_OFFSET, mEntryTable.data(), - static_cast(mEntryTable.byteSize())); + mEntryTable.byteSize()); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -465,7 +475,9 @@ esp_err_t Page::mLoadEntryTable() if (end > ENTRY_COUNT) { end = ENTRY_COUNT; } - for (size_t i = 0; i < end; ++i) { + size_t span; + for (size_t i = 0; i < end; i += span) { + span = 1; if (mEntryTable.get(i) == EntryState::ERASED) { lastItemIndex = INVALID_ENTRY; continue; @@ -478,6 +490,11 @@ esp_err_t Page::mLoadEntryTable() mState = PageState::INVALID; return err; } + + mHashList.insert(item, i); + + // search for potential duplicate item + size_t duplicateIndex = mHashList.find(0, item); if (item.crc32 != item.calculateCrc32()) { err = eraseEntryAndSpan(i); @@ -488,25 +505,26 @@ esp_err_t Page::mLoadEntryTable() continue; } - mHashList.insert(item, i); - - if (item.datatype != ItemType::BLOB && item.datatype != ItemType::SZ) { - continue; - } - - size_t span = item.span; - bool needErase = false; - for (size_t j = i; j < i + span; ++j) { - if (mEntryTable.get(j) != EntryState::WRITTEN) { - needErase = true; - lastItemIndex = INVALID_ENTRY; - break; + + if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) { + span = item.span; + bool needErase = false; + for (size_t j = i; j < i + span; ++j) { + if (mEntryTable.get(j) != EntryState::WRITTEN) { + needErase = true; + lastItemIndex = INVALID_ENTRY; + break; + } + } + if (needErase) { + eraseEntryAndSpan(i); + continue; } } - if (needErase) { - eraseEntryAndSpan(i); + + if (duplicateIndex < i) { + eraseEntryAndSpan(duplicateIndex); } - i += span - 1; } // check that last item is not duplicate @@ -559,7 +577,7 @@ esp_err_t Page::initialize() header.mSeqNumber = mSeqNumber; header.mCrc32 = header.calculateCrc32(); - auto rc = spi_flash_write(mBaseAddress, reinterpret_cast(&header), sizeof(header)); + auto rc = spi_flash_write(mBaseAddress, &header, sizeof(header)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -577,7 +595,8 @@ esp_err_t Page::alterEntryState(size_t index, EntryState state) mEntryTable.set(index, state); size_t wordToWrite = mEntryTable.getWordIndex(index); uint32_t word = mEntryTable.data()[wordToWrite]; - auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordToWrite) * 4, &word, 4); + auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordToWrite) * 4, + &word, sizeof(word)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -600,7 +619,8 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state) } if (nextWordIndex != wordIndex) { uint32_t word = mEntryTable.data()[wordIndex]; - auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordIndex) * 4, &word, 4); + auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordIndex) * 4, + &word, 4); if (rc != ESP_OK) { return rc; } @@ -612,7 +632,8 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state) esp_err_t Page::alterPageState(PageState state) { - auto rc = spi_flash_write(mBaseAddress, reinterpret_cast(&state), sizeof(state)); + uint32_t state_val = static_cast(state); + auto rc = spi_flash_write(mBaseAddress, &state_val, sizeof(state)); if (rc != ESP_OK) { mState = PageState::INVALID; return rc; @@ -623,7 +644,7 @@ esp_err_t Page::alterPageState(PageState state) esp_err_t Page::readEntry(size_t index, Item& dst) const { - auto rc = spi_flash_read(getEntryAddress(index), reinterpret_cast(&dst), sizeof(dst)); + auto rc = spi_flash_read(getEntryAddress(index), &dst, sizeof(dst)); if (rc != ESP_OK) { return rc; } @@ -635,19 +656,20 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si if (mState == PageState::CORRUPT || mState == PageState::INVALID || mState == PageState::UNINITIALIZED) { return ESP_ERR_NVS_NOT_FOUND; } - - if (itemIndex >= ENTRY_COUNT) { + + size_t findBeginIndex = itemIndex; + if (findBeginIndex >= ENTRY_COUNT) { return ESP_ERR_NVS_NOT_FOUND; } CachedFindInfo findInfo(nsIndex, datatype, key); if (mFindInfo == findInfo) { - itemIndex = mFindInfo.itemIndex(); + findBeginIndex = mFindInfo.itemIndex(); } size_t start = mFirstUsedEntry; - if (itemIndex > mFirstUsedEntry && itemIndex < ENTRY_COUNT) { - start = itemIndex; + if (findBeginIndex > mFirstUsedEntry && findBeginIndex < ENTRY_COUNT) { + start = findBeginIndex; } size_t end = mNextFreeEntry; @@ -741,7 +763,7 @@ esp_err_t Page::erase() mFirstUsedEntry = INVALID_ENTRY; mNextFreeEntry = INVALID_ENTRY; mState = PageState::UNINITIALIZED; - mHashList = HashList(); + mHashList.clear(); return ESP_OK; } @@ -769,7 +791,7 @@ void Page::invalidateCache() void Page::debugDump() const { - printf("state=%x addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n", mState, mBaseAddress, mSeqNumber, static_cast(mFirstUsedEntry), static_cast(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount); + printf("state=%x addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n", (int) mState, mBaseAddress, mSeqNumber, static_cast(mFirstUsedEntry), static_cast(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount); size_t skip = 0; for (size_t i = 0; i < ENTRY_COUNT; ++i) { printf("%3d: ", static_cast(i)); @@ -782,8 +804,12 @@ void Page::debugDump() const Item item; readEntry(i, item); if (skip == 0) { - printf("W ns=%2u type=%2u span=%3u key=\"%s\"\n", item.nsIndex, static_cast(item.datatype), item.span, item.key); - skip = item.span - 1; + printf("W ns=%2u type=%2u span=%3u key=\"%s\" len=%d\n", item.nsIndex, static_cast(item.datatype), item.span, item.key, (item.span != 1)?((int)item.varLength.dataSize):-1); + if (item.span > 0 && item.span <= ENTRY_COUNT - i) { + skip = item.span - 1; + } else { + skip = 0; + } } else { printf("D\n"); skip--; diff --git a/components/nvs_flash/src/nvs_pagemanager.cpp b/components/nvs_flash/src/nvs_pagemanager.cpp index 790ab7e19f..f4d02a7d40 100644 --- a/components/nvs_flash/src/nvs_pagemanager.cpp +++ b/components/nvs_flash/src/nvs_pagemanager.cpp @@ -49,7 +49,7 @@ esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount) return activatePage(); } else { uint32_t lastSeqNo; - assert(mPageList.back().getSeqNumber(lastSeqNo) == ESP_OK); + ESP_ERROR_CHECK( mPageList.back().getSeqNumber(lastSeqNo) ); mSeqNumber = lastSeqNo + 1; } @@ -142,7 +142,9 @@ esp_err_t PageManager::requestNewPage() Page* newPage = &mPageList.back(); Page* erasedPage = maxErasedItemsPageIt; +#ifndef NDEBUG size_t usedEntries = erasedPage->getUsedEntryCount(); +#endif err = erasedPage->markFreeing(); if (err != ESP_OK) { return err; diff --git a/components/nvs_flash/src/nvs_storage.cpp b/components/nvs_flash/src/nvs_storage.cpp index 4a217ebe18..cacfbd4022 100644 --- a/components/nvs_flash/src/nvs_storage.cpp +++ b/components/nvs_flash/src/nvs_storage.cpp @@ -71,8 +71,8 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount) esp_err_t Storage::findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item) { - size_t itemIndex = 0; for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { + size_t itemIndex = 0; auto err = it->findItem(nsIndex, datatype, key, itemIndex, item); if (err == ESP_OK) { page = it; @@ -123,8 +123,7 @@ esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key if (findPage) { if (findPage->state() == Page::PageState::UNINITIALIZED || findPage->state() == Page::PageState::INVALID) { - auto err = findItem(nsIndex, datatype, key, findPage, item); - assert(err == ESP_OK); + ESP_ERROR_CHECK( findItem(nsIndex, datatype, key, findPage, item) ); } err = findPage->eraseItem(nsIndex, datatype, key); if (err == ESP_ERR_FLASH_OP_FAIL) { diff --git a/components/nvs_flash/test/crc.cpp b/components/nvs_flash/test/crc.cpp index 288b58a323..4cbb9be9ec 100644 --- a/components/nvs_flash/test/crc.cpp +++ b/components/nvs_flash/test/crc.cpp @@ -14,25 +14,51 @@ #include #include -extern "C" unsigned long crc32_le(unsigned long crc_in, unsigned char const* data, unsigned int length) -{ - uint32_t i; - bool bit; - uint8_t c; - uint32_t crc = (uint32_t) crc_in; +static const unsigned int crc32_le_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; - while (length--) { - c = *data++; - for (i = 0x80; i > 0; i >>= 1) { - bit = crc & 0x80000000; - if (c & i) { - bit = !bit; - } - crc <<= 1; - if (bit) { - crc ^= 0x04c11db7; - } - } + + +extern "C" unsigned int crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len) +{ + unsigned int i; + crc = ~crc; + for(i=0;i>8); } - return crc; + return ~crc; } + diff --git a/components/nvs_flash/test/spi_flash_emulation.cpp b/components/nvs_flash/test/spi_flash_emulation.cpp index 5185bd34cb..914efc1452 100644 --- a/components/nvs_flash/test/spi_flash_emulation.cpp +++ b/components/nvs_flash/test/spi_flash_emulation.cpp @@ -22,7 +22,7 @@ void spi_flash_emulator_set(SpiFlashEmulator* e) s_emulator = e; } -esp_err_t spi_flash_erase_sector(uint16_t sec) +esp_err_t spi_flash_erase_sector(size_t sec) { if (!s_emulator) { return ESP_ERR_FLASH_OP_TIMEOUT; @@ -35,26 +35,26 @@ esp_err_t spi_flash_erase_sector(uint16_t sec) return ESP_OK; } -esp_err_t spi_flash_write(uint32_t des_addr, const uint32_t *src_addr, uint32_t size) +esp_err_t spi_flash_write(size_t des_addr, const void *src_addr, size_t size) { if (!s_emulator) { return ESP_ERR_FLASH_OP_TIMEOUT; } - if (!s_emulator->write(des_addr, src_addr, size)) { + if (!s_emulator->write(des_addr, reinterpret_cast(src_addr), size)) { return ESP_ERR_FLASH_OP_FAIL; } return ESP_OK; } -esp_err_t spi_flash_read(uint32_t src_addr, uint32_t *des_addr, uint32_t size) +esp_err_t spi_flash_read(size_t src_addr, void *des_addr, size_t size) { if (!s_emulator) { return ESP_ERR_FLASH_OP_TIMEOUT; } - if (!s_emulator->read(des_addr, src_addr, size)) { + if (!s_emulator->read(reinterpret_cast(des_addr), src_addr, size)) { return ESP_ERR_FLASH_OP_FAIL; } diff --git a/components/nvs_flash/test/spi_flash_emulation.h b/components/nvs_flash/test/spi_flash_emulation.h index d5a242b240..14e56bab6e 100644 --- a/components/nvs_flash/test/spi_flash_emulation.h +++ b/components/nvs_flash/test/spi_flash_emulation.h @@ -44,7 +44,7 @@ public: spi_flash_emulator_set(nullptr); } - bool read(uint32_t* dest, uint32_t srcAddr, size_t size) const + bool read(uint32_t* dest, size_t srcAddr, size_t size) const { if (srcAddr % 4 != 0 || size % 4 != 0 || @@ -60,7 +60,7 @@ public: return true; } - bool write(uint32_t dstAddr, const uint32_t* src, size_t size) + bool write(size_t dstAddr, const uint32_t* src, size_t size) { uint32_t sectorNumber = dstAddr/SPI_FLASH_SEC_SIZE; if (sectorNumber < mLowerSectorBound || sectorNumber >= mUpperSectorBound) { @@ -74,11 +74,11 @@ public: return false; } - if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) { - return false; - } - for (size_t i = 0; i < size / 4; ++i) { + if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) { + return false; + } + uint32_t sv = src[i]; size_t pos = dstAddr / 4 + i; uint32_t& dv = mData[pos]; @@ -96,7 +96,7 @@ public: return true; } - bool erase(uint32_t sectorNumber) + bool erase(size_t sectorNumber) { size_t offset = sectorNumber * SPI_FLASH_SEC_SIZE / 4; if (offset > mData.size()) { @@ -141,6 +141,18 @@ public: { return reinterpret_cast(mData.data()); } + + void load(const char* filename) + { + FILE* f = fopen(filename, "rb"); + fseek(f, 0, SEEK_END); + off_t size = ftell(f); + assert(size % SPI_FLASH_SEC_SIZE == 0); + mData.resize(size); + fseek(f, 0, SEEK_SET); + auto s = fread(mData.data(), SPI_FLASH_SEC_SIZE, size / SPI_FLASH_SEC_SIZE, f); + assert(s == static_cast(size / SPI_FLASH_SEC_SIZE)); + } void clearStats() { diff --git a/components/nvs_flash/test/test_nvs.cpp b/components/nvs_flash/test/test_nvs.cpp index 3db9b45aeb..81bf7fd216 100644 --- a/components/nvs_flash/test/test_nvs.cpp +++ b/components/nvs_flash/test/test_nvs.cpp @@ -300,6 +300,27 @@ TEST_CASE("storage doesn't add duplicates within multiple pages", "[nvs]") CHECK(page.findItem(1, itemTypeOf(), "bar") == ESP_OK); } +TEST_CASE("storage can find items on second page if first is not fully written and has cached search data", "[nvs]") +{ + SpiFlashEmulator emu(3); + Storage storage; + CHECK(storage.init(0, 3) == ESP_OK); + int bar = 0; + uint8_t bigdata[100 * 32] = {0}; + // write one big chunk of data + ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "first", bigdata, sizeof(bigdata))); + + // write second one; it will not fit into the first page + ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "second", bigdata, sizeof(bigdata))); + + size_t size; + ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "first", size)); + CHECK(size == sizeof(bigdata)); + ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "second", size)); + CHECK(size == sizeof(bigdata)); +} + + TEST_CASE("can write and read variable length data lots of times", "[nvs]") { SpiFlashEmulator emu(8); @@ -894,7 +915,7 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey size_t totalOps = 0; int lastPercent = -1; - for (uint32_t errDelay = 4; ; ++errDelay) { + for (uint32_t errDelay = 0; ; ++errDelay) { INFO(errDelay); emu.randomize(seed); emu.clearStats(); @@ -903,23 +924,25 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey if (totalOps != 0) { int percent = errDelay * 100 / totalOps; - if (percent != lastPercent) { + if (percent > lastPercent) { printf("%d/%d (%d%%)\r\n", errDelay, static_cast(totalOps), percent); lastPercent = percent; } } - TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); nvs_handle handle; - TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); - size_t count = iter_count; - if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) { - nvs_close(handle); - break; + + if (nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) { + if (nvs_open("namespace1", NVS_READWRITE, &handle) == ESP_OK) { + if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) { + nvs_close(handle); + break; + } + nvs_close(handle); + } } - nvs_close(handle); TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); @@ -929,10 +952,163 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey CHECK(0); } nvs_close(handle); - totalOps = emu.getEraseOps() + emu.getWriteOps(); + totalOps = emu.getEraseOps() + emu.getWriteBytes() / 4; } } +TEST_CASE("test for memory leaks in open/set", "[leaks]") +{ + SpiFlashEmulator emu(10); + const uint32_t NVS_FLASH_SECTOR = 6; + const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3; + emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN); + TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); + + for (int i = 0; i < 100000; ++i) { + nvs_handle light_handle = 0; + char lightbulb[1024] = {12, 13, 14, 15, 16}; + TEST_ESP_OK(nvs_open("light", NVS_READWRITE, &light_handle)); + TEST_ESP_OK(nvs_set_blob(light_handle, "key", lightbulb, sizeof(lightbulb))); + TEST_ESP_OK(nvs_commit(light_handle)); + nvs_close(light_handle); + } +} + +TEST_CASE("duplicate items are removed", "[nvs][dupes]") +{ + SpiFlashEmulator emu(3); + { + // create one item + nvs::Page p; + p.load(0); + p.writeItem(1, "opmode", 3); + } + { + // add another two without deleting the first one + nvs::Item item(1, ItemType::U8, 1, "opmode"); + item.data[0] = 2; + item.crc32 = item.calculateCrc32(); + emu.write(3 * 32, reinterpret_cast(&item), sizeof(item)); + emu.write(4 * 32, reinterpret_cast(&item), sizeof(item)); + uint32_t mask = 0xFFFFFFEA; + emu.write(32, &mask, 4); + } + { + // load page and check that second item persists + nvs::Storage s; + s.init(0, 3); + uint8_t val; + ESP_ERROR_CHECK(s.readItem(1, "opmode", val)); + CHECK(val == 2); + } + { + Page p; + p.load(0); + CHECK(p.getErasedEntryCount() == 2); + CHECK(p.getUsedEntryCount() == 1); + } +} + +TEST_CASE("recovery after failure to write data", "[nvs]") +{ + SpiFlashEmulator emu(3); + const char str[] = "value 0123456789abcdef012345678value 0123456789abcdef012345678"; + + // make flash write fail exactly in Page::writeEntryData + emu.failAfter(17); + { + Storage storage; + TEST_ESP_OK(storage.init(0, 3)); + + TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_FLASH_OP_FAIL); + + // check that repeated operations cause an error + TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_NVS_INVALID_STATE); + + uint8_t val; + TEST_ESP_ERR(storage.readItem(1, ItemType::U8, "key", &val, sizeof(val)), ESP_ERR_NVS_NOT_FOUND); + } + { + // load page and check that data was erased + Page p; + p.load(0); + CHECK(p.getErasedEntryCount() == 3); + CHECK(p.getUsedEntryCount() == 0); + + // try to write again + TEST_ESP_OK(p.writeItem(1, ItemType::SZ, "key", str, strlen(str))); + } +} + +TEST_CASE("crc error in variable length item is handled", "[nvs]") +{ + SpiFlashEmulator emu(3); + const uint64_t before_val = 0xbef04e; + const uint64_t after_val = 0xaf7e4; + // write some data + { + Page p; + p.load(0); + TEST_ESP_OK(p.writeItem(0, "before", before_val)); + const char* str = "foobar"; + TEST_ESP_OK(p.writeItem(0, ItemType::SZ, "key", str, strlen(str))); + TEST_ESP_OK(p.writeItem(0, "after", after_val)); + } + // corrupt some data + uint32_t w; + CHECK(emu.read(&w, 32 * 3 + 8, sizeof(w))); + w &= 0xf000000f; + CHECK(emu.write(32 * 3 + 8, &w, sizeof(w))); + // load and check + { + Page p; + p.load(0); + CHECK(p.getUsedEntryCount() == 2); + CHECK(p.getErasedEntryCount() == 2); + + uint64_t val; + TEST_ESP_OK(p.readItem(0, "before", val)); + CHECK(val == before_val); + TEST_ESP_ERR(p.findItem(0, ItemType::SZ, "key"), ESP_ERR_NVS_NOT_FOUND); + TEST_ESP_OK(p.readItem(0, "after", val)); + CHECK(val == after_val); + } +} + + +TEST_CASE("read/write failure (TW8406)", "[nvs]") +{ + SpiFlashEmulator emu(3); + nvs_flash_init_custom(0, 3); + for (int attempts = 0; attempts < 3; ++attempts) { + int i = 0; + nvs_handle light_handle = 0; + char key[15] = {0}; + char data[76] = {12, 13, 14, 15, 16}; + uint8_t number = 20; + size_t data_len = sizeof(data); + + ESP_ERROR_CHECK(nvs_open("LIGHT", NVS_READWRITE, &light_handle)); + ESP_ERROR_CHECK(nvs_set_u8(light_handle, "RecordNum", number)); + for (i = 0; i < number; ++i) { + sprintf(key, "light%d", i); + ESP_ERROR_CHECK(nvs_set_blob(light_handle, key, data, sizeof(data))); + } + nvs_commit(light_handle); + + uint8_t get_number = 0; + ESP_ERROR_CHECK(nvs_get_u8(light_handle, "RecordNum", &get_number)); + REQUIRE(number == get_number); + for (i = 0; i < number; ++i) { + char data[76] = {0}; + sprintf(key, "light%d", i); + ESP_ERROR_CHECK(nvs_get_blob(light_handle, key, data, &data_len)); + } + nvs_close(light_handle); + } +} + + TEST_CASE("dump all performance data", "[nvs]") { std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl; diff --git a/components/nvs_flash/test/test_spi_flash_emulation.cpp b/components/nvs_flash/test/test_spi_flash_emulation.cpp index ea233da61b..0c77aa9669 100644 --- a/components/nvs_flash/test/test_spi_flash_emulation.cpp +++ b/components/nvs_flash/test/test_spi_flash_emulation.cpp @@ -30,7 +30,7 @@ TEST_CASE("flash starts with all bytes == 0xff", "[spi_flash_emu]") uint8_t sector[SPI_FLASH_SEC_SIZE]; for (int i = 0; i < 4; ++i) { - CHECK(spi_flash_read(0, reinterpret_cast(sector), sizeof(sector)) == ESP_OK); + CHECK(spi_flash_read(0, sector, sizeof(sector)) == ESP_OK); for (auto v: sector) { CHECK(v == 0xff); } @@ -83,7 +83,7 @@ TEST_CASE("after erase the sector is set to 0xff", "[spi_flash_emu]") TEST_CASE("read/write/erase operation times are calculated correctly", "[spi_flash_emu]") { SpiFlashEmulator emu(1); - uint32_t data[128]; + uint8_t data[512]; spi_flash_read(0, data, 4); CHECK(emu.getTotalTime() == 7); CHECK(emu.getReadOps() == 1); @@ -141,7 +141,7 @@ TEST_CASE("read/write/erase operation times are calculated correctly", "[spi_fla CHECK(emu.getTotalTime() == 37142); } -TEST_CASE("data is randomized predicatbly", "[spi_flash_emu]") +TEST_CASE("data is randomized predictably", "[spi_flash_emu]") { SpiFlashEmulator emu1(3); emu1.randomize(0x12345678); diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst new file mode 100644 index 0000000000..93e438dcf9 --- /dev/null +++ b/components/openssl/OpenSSL-APIs.rst @@ -0,0 +1,1797 @@ +OpenSSL-APIs +------------ + +This directory does not contain OpenSSL itself, but the code here can be used as a wrapper for applications using the OpenSSL API. +It uses mbedTLS to do the actual work, so anyone compiling openssl code needs the mbedtls library and header file. + +OpenSSL APIs not mentioned in this article are not open to public for the time, +also do not have the corresponding function. +If user calls it directly, it will always return an error or may show cannot link at compiling time. + +Chapter Introduction +==================== + +- Chapter 1. SSL Context Method Create +- Chapter 2. SSL Context Fucntion +- Chapter 3. SSL Fucntion +- Chapter 4. SSL X509 Certification and Private Key Function + + +Chapter 1. SSL Context Method Create +==================================== + +1.1 const SSL_METHOD* ``SSLv3_client_method`` (void) + + Arguments:: + + none + + Return:: + + SSLV3.0 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = SSLv3_client_method(); + + ... + } + +1.2 const SSL_METHOD* ``TLSv1_client_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.0 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_client_method(); + + ... + } + +1.3 const SSL_METHOD* ``TLSv1_1_client_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.1 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_1_client_method(); + + ... + } + +1.4 const SSL_METHOD* ``TLSv1_2_client_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_client_method(); + + ... + } + +1.5 const SSL_METHOD* ``TLS_client_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context client method point + + Description:: + + create the default SSL context method, it's always to be TLSV1.2 + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_client_method(); + + ... + } + +1.6 const SSL_METHOD* ``SSLv3_server_method`` (void) + + Arguments:: + + none + + Return:: + + SSLV3.0 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = SSLv3_server_method(); + + ... + } + +1.7 const SSL_METHOD* ``TLSv1_server_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.0 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_server_method(); + + ... + } + +1.8 const SSL_METHOD* ``TLSv1_1_server_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.1 version SSL context server method point + + Description:: + + create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_1_server_method(); + + ... + } + + +1.9 const SSL_METHOD* ``TLSv1_2_server_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_server_method(); + + ... + } + +1.10 const SSL_METHOD* ``TLS_server_method`` (void) + + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context server method point + + Description:: + + create the default SSL context method, it's always to be TLSV1.2 + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_server_method(); + + ... + } + + +Chapter 2. SSL Context Fucntion +=============================== + + +2.1 SSL_CTX* ``SSL_CTX_new`` (const SSL_METHOD *method) + + Arguments:: + + method - the SSL context method point + + Return:: + + context point + + Description:: + + create a SSL context + + Example:: + + void example(void) + { + SSL_CTX *ctx = SSL_CTX_new(SSLv3_server_method()); + + ... + } + + +2.2 ``void SSL_CTX_free`` (SSL_CTX *ctx) + + Arguments:: + + ctx - the SSL context point + + Return:: + + none + + Description:: + + free a SSL context + + Example:: + + void example(void) + { + SSL_CTX *ctx; + + ... ... + + SSL_CTX_free(ctx); + } + + +2.3 ``int SSL_CTX_set_ssl_version`` (SSL_CTX *ctx, const SSL_METHOD *meth) + + Arguments:: + + ctx - SSL context point + meth - SSL method point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set the SSL context version + + Example:: + + void example(void) + { + SSL_CTX *ctx; + const SSL_METHOD *meth; + + ... ... + + SSL_CTX_set_ssl_version(ctx, meth); + } + + +2.4 const SSL_METHOD* ``SSL_CTX_get_ssl_method`` (SSL_CTX *ctx) + + Arguments:: + + ctx - SSL context point + + Return:: + + SSL context method + + Description:: + + get the SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method; + SSL_CTX *ctx; + + ... ... + + method = SSL_CTX_get_ssl_method(ctx); + } + + + +Chapter 3. SSL Fucntion +======================= + + +3.1 SSL* ``SSL_new`` (SSL_CTX *ctx) + + Arguments:: + + ctx - SSL context point + + Return:: + + SSL method + + Description:: + + create a SSL + + Example:: + + void example(void) + { + SSL *ssl; + SSL_CTX *ctx; + + ... ... + + ssl = SSL_new(ctx); + } + + +3.2 void ``SSL_free`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + none + + Description:: + + free SSL + + Example:: + + void example(void) + { + SSL *ssl; + + ... ... + + SSL_free(ssl); + } + + +3.3 int ``SSL_do_handshake`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description:: + + perform the SSL handshake + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_do_handshake(ssl); + } + + +3.4 int ``SSL_connect`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description:: + + connect to the remote SSL server + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_connect(ssl); + } + + +3.5 int ``SSL_accept`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description:: + + accept the remote connection + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_accept(ssl); + } + + +3.6 int ``SSL_shutdown`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description:: + + shutdown the connection + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_shutdown(ssl); + } + + +3.7 int ``SSL_clear`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + shutdown the connection + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_clear(ssl); + } + + +3.8 int ``SSL_read`` (SSL *ssl, void *buffer, int len) + + Arguments:: + + ssl - point + buffer - data buffer point + len - data length + + Return:: + + > 0 : OK, and return received data bytes + = 0 : no data received or connection is closed + < 0 : an error catch + + Description:: + + read data from remote + + Example:: + + void example(void) + { + SSL *ssl; + char *buf; + int len; + int ret; + + ... ... + + ret = SSL_read(ssl, buf, len); + } + +3.9 int ``SSL_write`` (SSL *ssl, const void *buffer, int len) + + Arguments:: + + ssl - SSL point + buffer - data buffer point + len - data length + + Return:: + + > 0 : OK, and return received data bytes + = 0 : no data sent or connection is closed + < 0 : an error catch + + Description:: + + send the data to remote + + Example:: + + void example(void) + { + SSL *ssl; + char *buf; + int len; + int ret; + + ... ... + + ret = SSL_write(ssl, buf, len); + } + + +3.10 ``SSL_CTX *SSL_get_SSL_CTX`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL context + + Description:: + + get SSL context of the SSL + + Example:: + + void example(void) + { + SSL *ssl; + SSL_CTX *ctx; + + ... ... + + ctx = SSL_get_SSL_CTX(ssl); + } + + +3.11 int ``SSL_get_shutdown`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + shutdown mode + + Description:: + + get SSL shutdown mode + + Example:: + + void example(void) + { + SSL *ssl; + int mode; + + ... ... + + mode = SSL_get_SSL_CTX(ssl); + } + + +3.12 void ``SSL_set_shutdown`` (SSL *ssl, int mode) + + Arguments:: + + ssl - SSL point + + Return:: + + shutdown mode + + Description:: + + set SSL shutdown mode + + Example:: + + void example(void) + { + SSL *ssl; + int mode = 0; + + ... ... + + SSL_set_shutdown(ssl, mode); + } + + +3.13 const SSL_METHOD* ``SSL_get_ssl_method`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL method + + Description:: + + set SSL shutdown mode + + Example:: + + void example(void) + { + SSL *ssl; + const SSL_METHOD *method; + + ... ... + + method = SSL_get_ssl_method(ssl); + } + + +3.14 int ``SSL_set_ssl_method`` (SSL *ssl, const SSL_METHOD *method) + + Arguments:: + + ssl - SSL point + meth - SSL method point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set the SSL method + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + const SSL_METHOD *method; + + ... ... + + ret = SSL_set_ssl_method(ssl, method); + } + + +3.15 int ``SSL_pending`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + data bytes + + Description:: + + get received data bytes + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_pending(ssl); + } + + +3.16 int ``SSL_has_pending`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 1 : Yes + 0 : No + + Description:: + + check if data is received + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_has_pending(ssl); + } + + +3.17 int ``SSL_get_fd`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + >= 0 : socket id + < 0 : a error catch + + Description:: + + get the socket of the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_fd(ssl); + } + + +3.18 int ``SSL_get_rfd`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + >= 0 : socket id + < 0 : a error catch + + Description:: + + get the read only socket of the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_rfd(ssl); + } + + +3.19 int ``SSL_get_wfd`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + >= 0 : socket id + < 0 : a error catch + + Description:: + + get the write only socket of the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_wfd(ssl); + } + + +3.20 int ``SSL_set_fd`` (SSL *ssl, int fd) + + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set socket to SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_fd(ssl, socket); + } + + +3.21 int ``SSL_set_rfd`` (SSL *ssl, int fd) + + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set read only socket to SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_rfd(ssl, socket); + } + + +3.22 int ``SSL_set_wfd`` (SSL *ssl, int fd) + + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: + + 1 : OK + 0 : failed + + Description:: + + set write only socket to SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_wfd(ssl, socket); + } + + +3.23 int ``SSL_version`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL version + + Description:: + + get SSL version + + Example:: + + void example(void) + { + int version; + SSL *ssl; + + ... ... + + version = SSL_version(ssl); + } + + +3.24 const char* ``SSL_get_version`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL version string + + Description:: + + get the SSL current version string + + Example:: + + void example(void) + { + char *version; + SSL *ssl; + + ... ... + + version = SSL_get_version(ssl); + } + + +3.25 OSSL_HANDSHAKE_STATE ``SSL_get_state`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL state + + Description:: + + get the SSL state + + Example:: + + void example(void) + { + OSSL_HANDSHAKE_STATE state; + SSL *ssl; + + ... ... + + state = SSL_get_state(ssl); + } + + +3.26 const char* ``SSL_alert_desc_string`` (int value) + + Arguments:: + + value - SSL description + + Return:: + + alert value string + + Description:: + + get alert description string + + Example:: + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_desc_string(val); + } + + +3.27 const char* ``SSL_alert_desc_string_long`` (int value) + + Arguments:: + + value - SSL description + + Return:: + + alert value long string + + Description:: + + get alert description long string + + Example:: + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_desc_string_long(val); + } + + +3.28 const char* ``SSL_alert_type_string`` (int value) + + Arguments:: + + value - SSL type description + + Return:: + + alert type string + + Description:: + + get alert type string + + Example:: + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_type_string(val); + } + + +3.29 const char* ``SSL_alert_type_string_long`` (int value) + + Arguments:: + + value - SSL type description + + Return:: + + alert type long string + + Description:: + + get alert type long string + + Example:: + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_type_string_long(val); + } + +3.30 const char* ``SSL_rstate_string`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state string + + Description:: + + get the state string where SSL is reading + + Example:: + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_rstate_string(ssl); + } + + +3.31 const char* ``SSL_rstate_string_long`` (SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state long string + + Description:: + + get the state long string where SSL is reading + + Example:: + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_rstate_string_long(ssl); + } + + +3.32 const char* ``SSL_state_string`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state string + + Description:: + + get the state string + + Example:: + + void example(void) + { + SSL *ssl; + const char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.33 char* ``SSL_state_string_long`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state long string + + Description:: + + get the state long string + + Example:: + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.34 int ``SSL_get_error`` (const SSL *ssl, int ret_code) + + Arguments:: + + ssl - SSL point + ret_code - SSL return code + + Return:: + + SSL error number + + Description:: + + get SSL error code + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + int err; + + ... ... + + err = SSL_get_error(ssl, ret); + } + +3.35 int ``SSL_want`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + specifical statement + + Description:: + + get the SSL specifical statement + + Example:: + + void example(void) + { + SSL *ssl; + int state; + + ... ... + + state = SSL_want(ssl); + } + + +3.36 int ``SSL_want_nothing`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 0 : false + 1 : true + + Description:: + + check if SSL want nothing + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want(ssl); + } + + +3.37 int ``SSL_want_read`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 0 : false + 1 : true + + Description:: + + check if SSL want to read + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want_read(ssl); + } + + +3.38 int ``SSL_want_write`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + 0 : false + 1 : true + + Description:: + + check if SSL want to write + + Example:: + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want_write(ssl); + } + + +Chapter 4. SSL X509 Certification and Private Key Function +========================================================== + + +4.1 X509* ``d2i_X509`` (X509 **cert, const unsigned char *buffer, long len) + + Arguments:: + + cert - a point pointed to X509 certification + buffer - a point pointed to the certification context memory point + length - certification bytes + + Return:: + + X509 certification object point + + Description:: + + load a character certification context into system context. If '*cert' is pointed to the + certification, then load certification into it. Or create a new X509 certification object + + Example:: + + void example(void) + { + X509 *new; + X509 *cert; + unsigned char *buffer; + long len; + ... ... + + new = d2i_X509(&cert, buffer, len); + } + + +4.2 int ``SSL_add_client_CA`` (SSL *ssl, X509 *x) + + Arguments:: + + ssl - SSL point + x - CA certification point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + add CA client certification into the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + X509 *new; + + ... ... + + ret = SSL_add_client_CA(ssl, new); + } + + +4.3 int ``SSL_CTX_add_client_CA`` (SSL_CTX *ctx, X509 *x) + + Arguments:: + + ctx - SSL context point + x - CA certification point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + add CA client certification into the SSL context + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx; + X509 *new; + + ... ... + + ret = SSL_add_clSSL_CTX_add_client_CAient_CA(ctx, new); + } + + +4.4 X509* ``SSL_get_certificate`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + SSL certification point + + Description:: + + get the SSL certification point + + Example:: + + void example(void) + { + SSL *ssl; + X509 *cert; + + ... ... + + cert = SSL_get_certificate(ssl); + } + + +4.5 long ``SSL_get_verify_result`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + the result of verifying + + Description:: + + get the verifying result of the SSL certification + + Example:: + + void example(void) + { + SSL *ssl; + long ret; + + ... ... + + ret = SSL_get_verify_result(ssl); + } + + +4.6 int ``SSL_CTX_use_certificate`` (SSL_CTX *ctx, X509 *x) + + Arguments:: + + ctx - the SSL context point + pkey - certification object point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the certification into the SSL_CTX or SSL object + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx + X509 *new; + + ... ... + + ret = SSL_CTX_use_certificate(ctx, new); + } + + +4.7 int ``SSL_CTX_use_certificate_ASN1`` (SSL_CTX *ctx, int len, const unsigned char *d) + + Arguments:: + + ctx - SSL context point + len - certification length + d - data point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the ASN1 certification into SSL context + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx; + const unsigned char *buf; + int len; + + ... ... + + ret = SSL_CTX_use_certificate_ASN1(ctx, len, buf); + } + + +4.8 int ``SSL_CTX_use_PrivateKey`` (SSL_CTX *ctx, EVP_PKEY *pkey) + + Arguments:: + + ctx - SSL context point + pkey - private key object point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the private key into the context object + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx; + EVP_PKEY *pkey; + + ... ... + + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + } + + +4.9 int ``SSL_CTX_use_PrivateKey_ASN1`` (int pk, SSL_CTX *ctx, const unsigned char *d, long len) + + Arguments:: + + ctx - SSL context point + d - data point + len - private key length + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the ASN1 private key into SSL context + + Example:: + + void example(void) + { + int ret; + int pk; + SSL_CTX *ctx; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_CTX_use_PrivateKey_ASN1(pk, ctx, buf, len); + } + + +4.10 int ``SSL_CTX_use_RSAPrivateKey_ASN1`` (SSL_CTX *ctx, const unsigned char *d, long len) + + Arguments:: + + ctx - SSL context point + d - data point + len - private key length + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load the RSA ASN1 private key into SSL context + + Example:: + + void example(void) + { + int ret; + SSL_CTX *ctx; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_CTX_use_RSAPrivateKey_ASN1(ctx, buf, len); + } + + +4.11 int ``SSL_use_certificate_ASN1`` (SSL *ssl, int len, const unsigned char *d) + + Arguments:: + + ssl - SSL point + len - data bytes + d - data point + + Return:: + + 1 : OK + 0 : failed + + Description:: + + load certification into the SSL + + Example:: + + void example(void) + { + int ret; + SSL *ssl; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_use_certificate_ASN1(ssl, len, buf); + } + + +4.12 X509* ``SSL_get_peer_certificate`` (const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + peer certification + + Description:: + + get peer certification + + Example:: + + void example(void) + { + SSL *ssl; + X509 *peer; + + ... ... + + peer = SSL_get_peer_certificate(ssl); + } + diff --git a/components/openssl/component.mk b/components/openssl/component.mk new file mode 100644 index 0000000000..be40549d20 --- /dev/null +++ b/components/openssl/component.mk @@ -0,0 +1,9 @@ +# +# Component Makefile +# + +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := include/internal include/platform include/openssl + +COMPONENT_SRCDIRS := library platform + diff --git a/components/openssl/include/internal/ssl3.h b/components/openssl/include/internal/ssl3.h new file mode 100644 index 0000000000..007b392f3e --- /dev/null +++ b/components/openssl/include/internal/ssl3.h @@ -0,0 +1,44 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL3_H_ +#define _SSL3_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +# define SSL3_AD_CLOSE_NOTIFY 0 +# define SSL3_AD_UNEXPECTED_MESSAGE 10/* fatal */ +# define SSL3_AD_BAD_RECORD_MAC 20/* fatal */ +# define SSL3_AD_DECOMPRESSION_FAILURE 30/* fatal */ +# define SSL3_AD_HANDSHAKE_FAILURE 40/* fatal */ +# define SSL3_AD_NO_CERTIFICATE 41 +# define SSL3_AD_BAD_CERTIFICATE 42 +# define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +# define SSL3_AD_CERTIFICATE_REVOKED 44 +# define SSL3_AD_CERTIFICATE_EXPIRED 45 +# define SSL3_AD_CERTIFICATE_UNKNOWN 46 +# define SSL3_AD_ILLEGAL_PARAMETER 47/* fatal */ + +# define SSL3_AL_WARNING 1 +# define SSL3_AL_FATAL 2 + +#define SSL3_VERSION 0x0300 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_cert.h b/components/openssl/include/internal/ssl_cert.h new file mode 100644 index 0000000000..86cf31ad51 --- /dev/null +++ b/components/openssl/include/internal/ssl_cert.h @@ -0,0 +1,55 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_CERT_H_ +#define _SSL_CERT_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" + +/** + * @brief create a certification object include private key object according to input certification + * + * @param ic - input certification point + * + * @return certification object point + */ +CERT *__ssl_cert_new(CERT *ic); + +/** + * @brief create a certification object include private key object + * + * @param none + * + * @return certification object point + */ +CERT* ssl_cert_new(void); + +/** + * @brief free a certification object + * + * @param cert - certification object point + * + * @return none + */ +void ssl_cert_free(CERT *cert); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_code.h b/components/openssl/include/internal/ssl_code.h new file mode 100644 index 0000000000..80fdbb20f3 --- /dev/null +++ b/components/openssl/include/internal/ssl_code.h @@ -0,0 +1,124 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_CODE_H_ +#define _SSL_CODE_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl3.h" +#include "tls1.h" +#include "x509_vfy.h" + +/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ +# define SSL_SENT_SHUTDOWN 1 +# define SSL_RECEIVED_SHUTDOWN 2 + +# define SSL_VERIFY_NONE 0x00 +# define SSL_VERIFY_PEER 0x01 +# define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +# define SSL_VERIFY_CLIENT_ONCE 0x04 + +/* + * The following 3 states are kept in ssl->rlayer.rstate when reads fail, you + * should not need these + */ +# define SSL_ST_READ_HEADER 0xF0 +# define SSL_ST_READ_BODY 0xF1 +# define SSL_ST_READ_DONE 0xF2 + +# define SSL_NOTHING 1 +# define SSL_WRITING 2 +# define SSL_READING 3 +# define SSL_X509_LOOKUP 4 +# define SSL_ASYNC_PAUSED 5 +# define SSL_ASYNC_NO_JOBS 6 + + +# define SSL_ERROR_NONE 0 +# define SSL_ERROR_SSL 1 +# define SSL_ERROR_WANT_READ 2 +# define SSL_ERROR_WANT_WRITE 3 +# define SSL_ERROR_WANT_X509_LOOKUP 4 +# define SSL_ERROR_SYSCALL 5/* look at error stack/return value/errno */ +# define SSL_ERROR_ZERO_RETURN 6 +# define SSL_ERROR_WANT_CONNECT 7 +# define SSL_ERROR_WANT_ACCEPT 8 +# define SSL_ERROR_WANT_ASYNC 9 +# define SSL_ERROR_WANT_ASYNC_JOB 10 + +/* Message flow states */ +typedef enum { + /* No handshake in progress */ + MSG_FLOW_UNINITED, + /* A permanent error with this connection */ + MSG_FLOW_ERROR, + /* We are about to renegotiate */ + MSG_FLOW_RENEGOTIATE, + /* We are reading messages */ + MSG_FLOW_READING, + /* We are writing messages */ + MSG_FLOW_WRITING, + /* Handshake has finished */ + MSG_FLOW_FINISHED +} MSG_FLOW_STATE; + +/* SSL subsystem states */ +typedef enum { + TLS_ST_BEFORE, + TLS_ST_OK, + DTLS_ST_CR_HELLO_VERIFY_REQUEST, + TLS_ST_CR_SRVR_HELLO, + TLS_ST_CR_CERT, + TLS_ST_CR_CERT_STATUS, + TLS_ST_CR_KEY_EXCH, + TLS_ST_CR_CERT_REQ, + TLS_ST_CR_SRVR_DONE, + TLS_ST_CR_SESSION_TICKET, + TLS_ST_CR_CHANGE, + TLS_ST_CR_FINISHED, + TLS_ST_CW_CLNT_HELLO, + TLS_ST_CW_CERT, + TLS_ST_CW_KEY_EXCH, + TLS_ST_CW_CERT_VRFY, + TLS_ST_CW_CHANGE, + TLS_ST_CW_NEXT_PROTO, + TLS_ST_CW_FINISHED, + TLS_ST_SW_HELLO_REQ, + TLS_ST_SR_CLNT_HELLO, + DTLS_ST_SW_HELLO_VERIFY_REQUEST, + TLS_ST_SW_SRVR_HELLO, + TLS_ST_SW_CERT, + TLS_ST_SW_KEY_EXCH, + TLS_ST_SW_CERT_REQ, + TLS_ST_SW_SRVR_DONE, + TLS_ST_SR_CERT, + TLS_ST_SR_KEY_EXCH, + TLS_ST_SR_CERT_VRFY, + TLS_ST_SR_NEXT_PROTO, + TLS_ST_SR_CHANGE, + TLS_ST_SR_FINISHED, + TLS_ST_SW_SESSION_TICKET, + TLS_ST_SW_CERT_STATUS, + TLS_ST_SW_CHANGE, + TLS_ST_SW_FINISHED +} OSSL_HANDSHAKE_STATE; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h new file mode 100644 index 0000000000..887fe2e82b --- /dev/null +++ b/components/openssl/include/internal/ssl_dbg.h @@ -0,0 +1,92 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_DEBUG_H_ +#define _SSL_DEBUG_H_ + +#include "platform/ssl_opt.h" +#include "platform/ssl_port.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#ifndef SSL_DEBUG_ENBALE +#define SSL_DEBUG_ENBALE 0 +#endif + +#ifndef SSL_DEBUG_LEVEL +#define SSL_DEBUG_LEVEL 0 +#endif + +#ifndef SSL_ASSERT_ENABLE +#define SSL_ASSERT_ENABLE 0 +#endif + +#ifndef SSL_DEBUG_LOCATION_ENABLE +#define SSL_DEBUG_LOCATION_ENABLE 0 +#endif + +#if SSL_DEBUG_ENBALE + #if !defined(SSL_PRINT_LOG) || !defined(SSL_ERROR_LOG) || !defined(SSL_LOCAL_LOG) + #include "stdio.h" + extern int printf(const char *fmt, ...); + #ifndef SSL_PRINT_LOG + #define SSL_PRINT_LOG printf + #endif + #ifndef SSL_ERROR_LOG + #define SSL_ERROR_LOG printf + #endif + #ifndef SSL_LOCAL_LOG + #define SSL_LOCAL_LOG printf + #endif + #endif +#else + #ifdef SSL_PRINT_LOG + #undef SSL_PRINT_LOG + #define SSL_PRINT_LOG(...) + #endif + #ifdef SSL_ERROR_LOG + #undef SSL_ERROR_LOG + #define SSL_ERROR_LOG(...) + #endif + #ifdef SSL_LOCAL_LOG + #undef SSL_LOCAL_LOG + #define SSL_LOCAL_LOG(...) + #endif +#endif + +#if SSL_DEBUG_LOCATION_ENABLE + #define SSL_DEBUG_LOCATION() SSL_LOCAL_LOG("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__) +#else + #define SSL_DEBUG_LOCATION() +#endif + +#if SSL_ASSERT_ENABLE + #define SSL_ASSERT(s) { if (!(s)) { SSL_DEBUG_LOCATION(); } } +#else + #define SSL_ASSERT(s) +#endif + +#define SSL_ERR(err, go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_ERROR_LOG(fmt, ##__VA_ARGS__); ret = err; goto go; } + +#define SSL_RET(go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_ERROR_LOG(fmt, ##__VA_ARGS__); goto go; } + +#define SSL_DEBUG(level, fmt, ...) { if (level > SSL_DEBUG_LEVEL) {SSL_PRINT_LOG(fmt, ##__VA_ARGS__);} } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_lib.h b/components/openssl/include/internal/ssl_lib.h new file mode 100644 index 0000000000..bf7de22fdf --- /dev/null +++ b/components/openssl/include/internal/ssl_lib.h @@ -0,0 +1,28 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_LIB_H_ +#define _SSL_LIB_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h new file mode 100644 index 0000000000..cd2f8c0533 --- /dev/null +++ b/components/openssl/include/internal/ssl_methods.h @@ -0,0 +1,121 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_METHODS_H_ +#define _SSL_METHODS_H_ + +#include "ssl_types.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * TLS method function implement + */ +#define IMPLEMENT_TLS_METHOD_FUNC(func_name, \ + new, free, \ + handshake, shutdown, clear, \ + read, send, pending, \ + set_fd, get_fd, \ + set_bufflen, \ + get_verify_result, \ + get_state) \ + static const SSL_METHOD_FUNC func_name LOCAL_ATRR = { \ + new, \ + free, \ + handshake, \ + shutdown, \ + clear, \ + read, \ + send, \ + pending, \ + set_fd, \ + get_fd, \ + set_bufflen, \ + get_verify_result, \ + get_state \ + }; + +#define IMPLEMENT_TLS_METHOD(ver, mode, fun, func_name) \ + const SSL_METHOD* func_name(void) { \ + static const SSL_METHOD func_name##_data LOCAL_ATRR = { \ + ver, \ + mode, \ + &(fun), \ + }; \ + return &func_name##_data; \ + } + +#define IMPLEMENT_SSL_METHOD(ver, mode, fun, func_name) \ + const SSL_METHOD* func_name(void) { \ + static const SSL_METHOD func_name##_data LOCAL_ATRR = { \ + ver, \ + mode, \ + &(fun), \ + }; \ + return &func_name##_data; \ + } + +#define IMPLEMENT_X509_METHOD(func_name, \ + new, \ + free, \ + load, \ + show_info) \ + const X509_METHOD* func_name(void) { \ + static const X509_METHOD func_name##_data LOCAL_ATRR = { \ + new, \ + free, \ + load, \ + show_info \ + }; \ + return &func_name##_data; \ + } + +#define IMPLEMENT_PKEY_METHOD(func_name, \ + new, \ + free, \ + load) \ + const PKEY_METHOD* func_name(void) { \ + static const PKEY_METHOD func_name##_data LOCAL_ATRR = { \ + new, \ + free, \ + load \ + }; \ + return &func_name##_data; \ + } + +/** + * @brief get X509 object method + * + * @param none + * + * @return X509 object method point + */ +const X509_METHOD* X509_method(void); + +/** + * @brief get private key object method + * + * @param none + * + * @return private key object method point + */ +const PKEY_METHOD* EVP_PKEY_method(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_pkey.h b/components/openssl/include/internal/ssl_pkey.h new file mode 100644 index 0000000000..e790fcc995 --- /dev/null +++ b/components/openssl/include/internal/ssl_pkey.h @@ -0,0 +1,86 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_PKEY_H_ +#define _SSL_PKEY_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" + +/** + * @brief create a private key object according to input private key + * + * @param ipk - input private key point + * + * @return new private key object point + */ +EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk); + +/** + * @brief create a private key object + * + * @param none + * + * @return private key object point + */ +EVP_PKEY* EVP_PKEY_new(void); + +/** + * @brief load a character key context into system context. If '*a' is pointed to the + * private key, then load key into it. Or create a new private key object + * + * @param type - private key type + * @param a - a point pointed to a private key point + * @param pp - a point pointed to the key context memory point + * @param length - key bytes + * + * @return private key object point + */ +EVP_PKEY* d2i_PrivateKey(int type, + EVP_PKEY **a, + const unsigned char **pp, + long length); + +/** + * @brief free a private key object + * + * @param pkey - private key object point + * + * @return none + */ +void EVP_PKEY_free(EVP_PKEY *x); + +/** + * @brief load private key into the SSL + * + * @param type - private key type + * @param ssl - SSL point + * @param len - data bytes + * @param d - data point + * + * @return result + * 0 : failed + * 1 : OK + */ + int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_stack.h b/components/openssl/include/internal/ssl_stack.h new file mode 100644 index 0000000000..7a7051a026 --- /dev/null +++ b/components/openssl/include/internal/ssl_stack.h @@ -0,0 +1,52 @@ +#ifndef _SSL_STACK_H_ +#define _SSL_STACK_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" + +#define STACK_OF(type) struct stack_st_##type + +#define SKM_DEFINE_STACK_OF(t1, t2, t3) \ + STACK_OF(t1); \ + static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \ + { \ + return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \ + } \ + +#define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t) + +/** + * @brief create a openssl stack object + * + * @param c - stack function + * + * @return openssl stack object point + */ +OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c); + +/** + * @brief create a NULL function openssl stack object + * + * @param none + * + * @return openssl stack object point + */ +OPENSSL_STACK *OPENSSL_sk_new_null(void); + +/** + * @brief free openssl stack object + * + * @param openssl stack object point + * + * @return none + */ +void OPENSSL_sk_free(OPENSSL_STACK *stack); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h new file mode 100644 index 0000000000..5aaee94176 --- /dev/null +++ b/components/openssl/include/internal/ssl_types.h @@ -0,0 +1,288 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_TYPES_H_ +#define _SSL_TYPES_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_code.h" + +typedef void SSL_CIPHER; + +typedef void X509_STORE_CTX; +typedef void X509_STORE; + +typedef void RSA; + +typedef void STACK; +typedef void BIO; + +#define ossl_inline inline + +#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__) +#define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__) +#define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__) + +typedef int (*OPENSSL_sk_compfunc)(const void *, const void *); + +struct stack_st; +typedef struct stack_st OPENSSL_STACK; + +struct ssl_method_st; +typedef struct ssl_method_st SSL_METHOD; + +struct ssl_method_func_st; +typedef struct ssl_method_func_st SSL_METHOD_FUNC; + +struct record_layer_st; +typedef struct record_layer_st RECORD_LAYER; + +struct ossl_statem_st; +typedef struct ossl_statem_st OSSL_STATEM; + +struct ssl_session_st; +typedef struct ssl_session_st SSL_SESSION; + +struct ssl_ctx_st; +typedef struct ssl_ctx_st SSL_CTX; + +struct ssl_st; +typedef struct ssl_st SSL; + +struct cert_st; +typedef struct cert_st CERT; + +struct x509_st; +typedef struct x509_st X509; + +struct X509_VERIFY_PARAM_st; +typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM; + +struct evp_pkey_st; +typedef struct evp_pkey_st EVP_PKEY; + +struct x509_method_st; +typedef struct x509_method_st X509_METHOD; + +struct pkey_method_st; +typedef struct pkey_method_st PKEY_METHOD; + +struct stack_st { + + char **data; + + int num_alloc; + + OPENSSL_sk_compfunc c; +}; + +struct evp_pkey_st { + + void *pkey_pm; + + const PKEY_METHOD *method; +}; + +struct x509_st { + + /* X509 certification platform private point */ + void *x509_pm; + + const X509_METHOD *method; +}; + +struct cert_st { + + int sec_level; + + X509 *x509; + + EVP_PKEY *pkey; + +}; + +struct ossl_statem_st { + + MSG_FLOW_STATE state; + + int hand_state; +}; + +struct record_layer_st { + + int rstate; + + int read_ahead; +}; + +struct ssl_session_st { + + long timeout; + + long time; + + X509 *peer; +}; + +struct X509_VERIFY_PARAM_st { + + int depth; + +}; + +struct ssl_ctx_st +{ + int version; + + int references; + + unsigned long options; + + #if 0 + struct alpn_protocols alpn_protocol; + #endif + + const SSL_METHOD *method; + + CERT *cert; + + X509 *client_CA; + + int verify_mode; + + int (*default_verify_callback) (int ok, X509_STORE_CTX *ctx); + + long session_timeout; + + int read_ahead; + + int read_buffer_len; + + X509_VERIFY_PARAM param; +}; + +struct ssl_st +{ + /* protocol version(one of SSL3.0, TLS1.0, etc.) */ + int version; + + unsigned long options; + + /* shut things down(0x01 : sent, 0x02 : received) */ + int shutdown; + + CERT *cert; + + X509 *client_CA; + + SSL_CTX *ctx; + + const SSL_METHOD *method; + + RECORD_LAYER rlayer; + + /* where we are */ + OSSL_STATEM statem; + + SSL_SESSION *session; + + int verify_mode; + + int (*verify_callback) (int ok, X509_STORE_CTX *ctx); + + int rwstate; + + long verify_result; + + X509_VERIFY_PARAM param; + + int err; + + void (*info_callback) (const SSL *ssl, int type, int val); + + /* SSL low-level system arch point */ + void *ssl_pm; +}; + +struct ssl_method_st { + /* protocol version(one of SSL3.0, TLS1.0, etc.) */ + int version; + + /* SSL mode(client(0) , server(1), not known(-1)) */ + int endpoint; + + const SSL_METHOD_FUNC *func; +}; + +struct ssl_method_func_st { + + int (*ssl_new)(SSL *ssl); + + void (*ssl_free)(SSL *ssl); + + int (*ssl_handshake)(SSL *ssl); + + int (*ssl_shutdown)(SSL *ssl); + + int (*ssl_clear)(SSL *ssl); + + int (*ssl_read)(SSL *ssl, void *buffer, int len); + + int (*ssl_send)(SSL *ssl, const void *buffer, int len); + + int (*ssl_pending)(const SSL *ssl); + + void (*ssl_set_fd)(SSL *ssl, int fd, int mode); + + int (*ssl_get_fd)(const SSL *ssl, int mode); + + void (*ssl_set_bufflen)(SSL *ssl, int len); + + long (*ssl_get_verify_result)(const SSL *ssl); + + OSSL_HANDSHAKE_STATE (*ssl_get_state)(const SSL *ssl); +}; + +struct x509_method_st { + + int (*x509_new)(X509 *x, X509 *m_x); + + void (*x509_free)(X509 *x); + + int (*x509_load)(X509 *x, const unsigned char *buf, int len); + + int (*x509_show_info)(X509 *x); +}; + +struct pkey_method_st { + + int (*pkey_new)(EVP_PKEY *pkey, EVP_PKEY *m_pkey); + + void (*pkey_free)(EVP_PKEY *pkey); + + int (*pkey_load)(EVP_PKEY *pkey, const unsigned char *buf, int len); +}; + +typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h new file mode 100644 index 0000000000..840fbf1ec1 --- /dev/null +++ b/components/openssl/include/internal/ssl_x509.h @@ -0,0 +1,108 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_X509_H_ +#define _SSL_X509_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" +#include "ssl_stack.h" + +DEFINE_STACK_OF(X509_NAME) + +/** + * @brief create a X509 certification object according to input X509 certification + * + * @param ix - input X509 certification point + * + * @return new X509 certification object point + */ +X509* __X509_new(X509 *ix); + +/** + * @brief create a X509 certification object + * + * @param none + * + * @return X509 certification object point + */ +X509* X509_new(void); + +/** + * @brief load a character certification context into system context. If '*cert' is pointed to the + * certification, then load certification into it. Or create a new X509 certification object + * + * @param cert - a point pointed to X509 certification + * @param buffer - a point pointed to the certification context memory point + * @param length - certification bytes + * + * @return X509 certification object point + */ +X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); + +/** + * @brief free a X509 certification object + * + * @param x - X509 certification object point + * + * @return none + */ +void X509_free(X509 *x); + +/** + * @brief set SSL context client CA certification + * + * @param ctx - SSL context point + * @param x - X509 certification point + * + * @return result + * 0 : failed + * 1 : OK + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +/** + * @brief add CA client certification into the SSL + * + * @param ssl - SSL point + * @param x - X509 certification point + * + * @return result + * 0 : failed + * 1 : OK + */ +int SSL_add_client_CA(SSL *ssl, X509 *x); + +/** + * @brief load certification into the SSL + * + * @param ssl - SSL point + * @param len - data bytes + * @param d - data point + * + * @return result + * 0 : failed + * 1 : OK + * + */ +int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/tls1.h b/components/openssl/include/internal/tls1.h new file mode 100644 index 0000000000..a9da53e063 --- /dev/null +++ b/components/openssl/include/internal/tls1.h @@ -0,0 +1,55 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _TLS1_H_ +#define _TLS1_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +# define TLS1_AD_DECRYPTION_FAILED 21 +# define TLS1_AD_RECORD_OVERFLOW 22 +# define TLS1_AD_UNKNOWN_CA 48/* fatal */ +# define TLS1_AD_ACCESS_DENIED 49/* fatal */ +# define TLS1_AD_DECODE_ERROR 50/* fatal */ +# define TLS1_AD_DECRYPT_ERROR 51 +# define TLS1_AD_EXPORT_RESTRICTION 60/* fatal */ +# define TLS1_AD_PROTOCOL_VERSION 70/* fatal */ +# define TLS1_AD_INSUFFICIENT_SECURITY 71/* fatal */ +# define TLS1_AD_INTERNAL_ERROR 80/* fatal */ +# define TLS1_AD_INAPPROPRIATE_FALLBACK 86/* fatal */ +# define TLS1_AD_USER_CANCELLED 90 +# define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +# define TLS1_AD_UNSUPPORTED_EXTENSION 110 +# define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +# define TLS1_AD_UNRECOGNIZED_NAME 112 +# define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +# define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +# define TLS1_AD_UNKNOWN_PSK_IDENTITY 115/* fatal */ +# define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */ + +/* Special value for method supporting multiple versions */ +#define TLS_ANY_VERSION 0x10000 + +#define TLS1_VERSION 0x0301 +#define TLS1_1_VERSION 0x0302 +#define TLS1_2_VERSION 0x0303 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/internal/x509_vfy.h b/components/openssl/include/internal/x509_vfy.h new file mode 100644 index 0000000000..d5b0d1a213 --- /dev/null +++ b/components/openssl/include/internal/x509_vfy.h @@ -0,0 +1,111 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _X509_VFY_H_ +#define _X509_VFY_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define X509_V_OK 0 +#define X509_V_ERR_UNSPECIFIED 1 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 +#define X509_V_ERR_UNABLE_TO_GET_CRL 3 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5 +#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6 +#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7 +#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8 +#define X509_V_ERR_CERT_NOT_YET_VALID 9 +#define X509_V_ERR_CERT_HAS_EXPIRED 10 +#define X509_V_ERR_CRL_NOT_YET_VALID 11 +#define X509_V_ERR_CRL_HAS_EXPIRED 12 +#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13 +#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14 +#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15 +#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16 +#define X509_V_ERR_OUT_OF_MEM 17 +#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18 +#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20 +#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21 +#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22 +#define X509_V_ERR_CERT_REVOKED 23 +#define X509_V_ERR_INVALID_CA 24 +#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25 +#define X509_V_ERR_INVALID_PURPOSE 26 +#define X509_V_ERR_CERT_UNTRUSTED 27 +#define X509_V_ERR_CERT_REJECTED 28 +/* These are 'informational' when looking for issuer cert */ +#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29 +#define X509_V_ERR_AKID_SKID_MISMATCH 30 +#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31 +#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 +#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 +#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 +#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +#define X509_V_ERR_INVALID_NON_CA 37 +#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38 +#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39 +#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40 +#define X509_V_ERR_INVALID_EXTENSION 41 +#define X509_V_ERR_INVALID_POLICY_EXTENSION 42 +#define X509_V_ERR_NO_EXPLICIT_POLICY 43 +#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44 +#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45 +#define X509_V_ERR_UNNESTED_RESOURCE 46 +#define X509_V_ERR_PERMITTED_VIOLATION 47 +#define X509_V_ERR_EXCLUDED_VIOLATION 48 +#define X509_V_ERR_SUBTREE_MINMAX 49 +/* The application is not happy */ +#define X509_V_ERR_APPLICATION_VERIFICATION 50 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52 +#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 +#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54 +/* Another issuer check debug option */ +#define X509_V_ERR_PATH_LOOP 55 +/* Suite B mode algorithm violation */ +#define X509_V_ERR_SUITE_B_INVALID_VERSION 56 +#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57 +#define X509_V_ERR_SUITE_B_INVALID_CURVE 58 +#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59 +#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60 +#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61 +/* Host, email and IP check errors */ +#define X509_V_ERR_HOSTNAME_MISMATCH 62 +#define X509_V_ERR_EMAIL_MISMATCH 63 +#define X509_V_ERR_IP_ADDRESS_MISMATCH 64 +/* DANE TLSA errors */ +#define X509_V_ERR_DANE_NO_MATCH 65 +/* security level errors */ +#define X509_V_ERR_EE_KEY_TOO_SMALL 66 +#define X509_V_ERR_CA_KEY_TOO_SMALL 67 +#define X509_V_ERR_CA_MD_TOO_WEAK 68 +/* Caller error */ +#define X509_V_ERR_INVALID_CALL 69 +/* Issuer lookup error */ +#define X509_V_ERR_STORE_LOOKUP 70 +/* Certificate transparency */ +#define X509_V_ERR_NO_VALID_SCTS 71 + +#define X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION 72 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h new file mode 100644 index 0000000000..7f8eb88302 --- /dev/null +++ b/components/openssl/include/openssl/ssl.h @@ -0,0 +1,1737 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_H_ +#define _SSL_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "internal/ssl_x509.h" +#include "internal/ssl_pkey.h" + +/* +{ +*/ + +/** + * @brief create a SSL context + * + * @param method - the SSL context method point + * + * @return the context point + */ +SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); + +/** + * @brief free a SSL context + * + * @param method - the SSL context point + * + * @return none + */ +void SSL_CTX_free(SSL_CTX *ctx); + +/** + * @brief create a SSL + * + * @param ctx - the SSL context point + * + * @return the SSL point + */ +SSL* SSL_new(SSL_CTX *ctx); + +/** + * @brief free the SSL + * + * @param ssl - the SSL point + * + * @return none + */ +void SSL_free(SSL *ssl); + +/** + * @brief connect to the remote SSL server + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * -1 : failed + */ +int SSL_connect(SSL *ssl); + +/** + * @brief accept the remote connection + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * -1 : failed + */ +int SSL_accept(SSL *ssl); + +/** + * @brief read data from to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the received data buffer point + * @param len - the received data length + * + * @return result + * > 0 : OK, and return received data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_read(SSL *ssl, void *buffer, int len); + +/** + * @brief send the data to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the send data buffer point + * @param len - the send data length + * + * @return result + * > 0 : OK, and return sent data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_write(SSL *ssl, const void *buffer, int len); + +/** + * @brief get the verifying result of the SSL certification + * + * @param ssl - the SSL point + * + * @return the result of verifying + */ +long SSL_get_verify_result(const SSL *ssl); + +/** + * @brief shutdown the connection + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * 0 : shutdown is not finished + * -1 : an error catch + */ +int SSL_shutdown(SSL *ssl); + +/** + * @brief bind the socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_fd(SSL *ssl, int fd); + +/** + * @brief These functions load the private key into the SSL_CTX or SSL object + * + * @param ctx - the SSL context point + * @param pkey - private key object point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + +/** + * @brief These functions load the certification into the SSL_CTX or SSL object + * + * @param ctx - the SSL context point + * @param pkey - certification object point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the SSLV2.3 version SSL context client method + */ +const SSL_METHOD* SSLv23_client_method(void); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.0 version SSL context client method + */ +const SSL_METHOD* TLSv1_client_method(void); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the SSLV1.0 version SSL context client method + */ +const SSL_METHOD* SSLv3_client_method(void); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.1 version SSL context client method + */ +const SSL_METHOD* TLSv1_1_client_method(void); + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.2 version SSL context client method + */ +const SSL_METHOD* TLSv1_2_client_method(void); + + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the SSLV2.3 version SSL context server method + */ +const SSL_METHOD* SSLv23_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.1 version SSL context server method + */ +const SSL_METHOD* TLSv1_1_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.2 version SSL context server method + */ +const SSL_METHOD* TLSv1_2_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.0 version SSL context server method + */ +const SSL_METHOD* TLSv1_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the SSLV3.0 version SSL context server method + */ +const SSL_METHOD* SSLv3_server_method(void); + +/** + * @brief set the SSL context ALPN select callback function + * + * @param ctx - SSL context point + * @param cb - ALPN select callback function + * @param arg - ALPN select callback function entry private data point + * + * @return none + */ +void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), + void *arg); + + +/** + * @brief set the SSL context ALPN select protocol + * + * @param ctx - SSL context point + * @param protos - ALPN protocol name + * @param protos_len - ALPN protocol name bytes + * + * @return result + * 0 : OK + * 1 : failed + */ +int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, unsigned int protos_len); + +/** + * @brief set the SSL context next ALPN select callback function + * + * @param ctx - SSL context point + * @param cb - ALPN select callback function + * @param arg - ALPN select callback function entry private data point + * + * @return none + */ +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), + void *arg); + +/** + * @brief get SSL error code + * + * @param ssl - SSL point + * @param ret_code - SSL return code + * + * @return SSL error number + */ +int SSL_get_error(const SSL *ssl, int ret_code); + +/** + * @brief clear the SSL error code + * + * @param none + * + * @return none + */ +void ERR_clear_error(void); + +/** + * @brief get the current SSL error code + * + * @param none + * + * @return current SSL error number + */ +int ERR_get_error(void); + +/** + * @brief register the SSL error strings + * + * @param none + * + * @return none + */ +void ERR_load_SSL_strings(void); + +/** + * @brief initialize the SSL library + * + * @param none + * + * @return none + */ +void SSL_library_init(void); + +/** + * @brief generates a human-readable string representing the error code e + * and store it into the "ret" point memory + * + * @param e - error code + * @param ret - memory point to store the string + * + * @return the result string point + */ +char *ERR_error_string(unsigned long e, char *ret); + +/** + * @brief add the SSL context option + * + * @param ctx - SSL context point + * @param opt - new SSL context option + * + * @return the SSL context option + */ +unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt); + +/** + * @brief add the SSL context mode + * + * @param ctx - SSL context point + * @param mod - new SSL context mod + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_mode(SSL_CTX *ctx, int mod); + +/* +} +*/ + +/** + * @brief perform the SSL handshake + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + * -1 : a error catch + */ +int SSL_do_handshake(SSL *ssl); + +/** + * @brief get the SSL current version + * + * @param ssl - SSL point + * + * @return the version string + */ +const char *SSL_get_version(const SSL *ssl); + +/** + * @brief set the SSL context version + * + * @param ctx - SSL context point + * @param meth - SSL method point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); + +/** + * @brief get the bytes numbers which are to be read + * + * @param ssl - SSL point + * + * @return bytes number + */ +int SSL_pending(const SSL *ssl); + +/** + * @brief check if SSL want nothing + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_nothing(const SSL *ssl); + +/** + * @brief check if SSL want to read + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_read(const SSL *ssl); + +/** + * @brief check if SSL want to write + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_write(const SSL *ssl); + +/** + * @brief get the SSL context current method + * + * @param ctx - SSL context point + * + * @return the SSL context current method + */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); + +/** + * @brief get the SSL current method + * + * @param ssl - SSL point + * + * @return the SSL current method + */ +const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); + +/** + * @brief set the SSL method + * + * @param ssl - SSL point + * @param meth - SSL method point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); + +/** + * @brief add CA client certification into the SSL + * + * @param ssl - SSL point + * @param x - CA certification point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_add_client_CA(SSL *ssl, X509 *x); + +/** + * @brief add CA client certification into the SSL context + * + * @param ctx - SSL context point + * @param x - CA certification point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +/** + * @brief set the SSL CA certification list + * + * @param ssl - SSL point + * @param name_list - CA certification list + * + * @return none + */ +void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list); + +/** + * @brief set the SSL context CA certification list + * + * @param ctx - SSL context point + * @param name_list - CA certification list + * + * @return none + */ +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); + +/** + * @briefget the SSL CA certification list + * + * @param ssl - SSL point + * + * @return CA certification list + */ +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl); + +/** + * @brief get the SSL context CA certification list + * + * @param ctx - SSL context point + * + * @return CA certification list + */ +STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx); + +/** + * @brief get the SSL certification point + * + * @param ssl - SSL point + * + * @return SSL certification point + */ +X509 *SSL_get_certificate(const SSL *ssl); + +/** + * @brief get the SSL private key point + * + * @param ssl - SSL point + * + * @return SSL private key point + */ +EVP_PKEY *SSL_get_privatekey(const SSL *ssl); + +/** + * @brief set the SSL information callback function + * + * @param ssl - SSL point + * @param cb - information callback function + * + * @return none + */ +void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)); + +/** + * @brief get the SSL state + * + * @param ssl - SSL point + * + * @return SSL state + */ +OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); + +/** + * @brief set the SSL context read buffer length + * + * @param ctx - SSL context point + * @param len - read buffer length + * + * @return none + */ +void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); + +/** + * @brief set the SSL read buffer length + * + * @param ssl - SSL point + * @param len - read buffer length + * + * @return none + */ +void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); + +/** + * @brief set the SSL security level + * + * @param ssl - SSL point + * @param level - security level + * + * @return none + */ +void SSL_set_security_level(SSL *ssl, int level); + +/** + * @brief get the SSL security level + * + * @param ssl - SSL point + * + * @return security level + */ +int SSL_get_security_level(const SSL *ssl); + +/** + * @brief get the SSL verifying mode of the SSL context + * + * @param ctx - SSL context point + * + * @return verifying mode + */ +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); + +/** + * @brief get the SSL verifying depth of the SSL context + * + * @param ctx - SSL context point + * + * @return verifying depth + */ +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); + +/** + * @brief set the SSL context verifying of the SSL context + * + * @param ctx - SSL context point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); + +/** + * @brief set the SSL verifying of the SSL context + * + * @param ctx - SSL point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_set_verify(SSL *s, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); + +/** + * @brief set the SSL verify depth of the SSL context + * + * @param ctx - SSL context point + * @param depth - verifying depth + * + * @return none + */ +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); + +/** + * @brief certification verifying callback function + * + * @param preverify_ok - verifying result + * @param x509_ctx - X509 certification point + * + * @return verifying result + */ +int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx); + +/** + * @brief set the session timeout time + * + * @param ctx - SSL context point + * @param t - new session timeout time + * + * @return old session timeout time + */ +long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); + +/** + * @brief get the session timeout time + * + * @param ctx - SSL context point + * + * @return current session timeout time + */ +long SSL_CTX_get_timeout(const SSL_CTX *ctx); + +/** + * @brief set the SSL context cipher through the list string + * + * @param ctx - SSL context point + * @param str - cipher controller list string + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); + +/** + * @brief set the SSL cipher through the list string + * + * @param ssl - SSL point + * @param str - cipher controller list string + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_cipher_list(SSL *ssl, const char *str); + +/** + * @brief get the SSL cipher list string + * + * @param ssl - SSL point + * + * @return cipher controller list string + */ +const char *SSL_get_cipher_list(const SSL *ssl, int n); + +/** + * @brief get the SSL cipher + * + * @param ssl - SSL point + * + * @return current cipher + */ +const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl); + +/** + * @brief get the SSL cipher string + * + * @param ssl - SSL point + * + * @return cipher string + */ +const char *SSL_get_cipher(const SSL *ssl); + +/** + * @brief get the SSL context object X509 certification storage + * + * @param ctx - SSL context point + * + * @return x509 certification storage + */ +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); + +/** + * @brief set the SSL context object X509 certification store + * + * @param ctx - SSL context point + * @param store - X509 certification store + * + * @return none + */ +void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store); + +/** + * @brief get the SSL specifical statement + * + * @param ssl - SSL point + * + * @return specifical statement + */ +int SSL_want(const SSL *ssl); + +/** + * @brief check if the SSL is SSL_X509_LOOKUP state + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_want_x509_lookup(const SSL *ssl); + +/** + * @brief reset the SSL + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_clear(SSL *ssl); + +/** + * @brief get the socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_fd(const SSL *ssl); + +/** + * @brief get the read only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_rfd(const SSL *ssl); + +/** + * @brief get the write only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_wfd(const SSL *ssl); + +/** + * @brief set the SSL if we can read as many as data + * + * @param ssl - SSL point + * @param yes - enable the function + * + * @return none + */ +void SSL_set_read_ahead(SSL *s, int yes); + +/** + * @brief set the SSL context if we can read as many as data + * + * @param ctx - SSL context point + * @param yes - enbale the function + * + * @return none + */ +void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes); + +/** + * @brief get the SSL ahead signal if we can read as many as data + * + * @param ssl - SSL point + * + * @return SSL context ahead signal + */ +int SSL_get_read_ahead(const SSL *ssl); + +/** + * @brief get the SSL context ahead signal if we can read as many as data + * + * @param ctx - SSL context point + * + * @return SSL context ahead signal + */ +long SSL_CTX_get_read_ahead(SSL_CTX *ctx); + +/** + * @brief check if some data can be read + * + * @param ssl - SSL point + * + * @return + * 1 : there are bytes to be read + * 0 : no data + */ +int SSL_has_pending(const SSL *ssl); + +/** + * @brief load the X509 certification into SSL context + * + * @param ctx - SSL context point + * @param x - X509 certification point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);//loads the certificate x into ctx + +/** + * @brief load the ASN1 certification into SSL context + * + * @param ctx - SSL context point + * @param len - certification length + * @param d - data point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); + +/** + * @brief load the certification file into SSL context + * + * @param ctx - SSL context point + * @param file - certification file name + * @param type - certification encoding type + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); + +/** + * @brief load the certification chain file into SSL context + * + * @param ctx - SSL context point + * @param file - certification chain file name + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); + + +/** + * @brief load the ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - private key length + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len);//adds the private key of type pk stored at memory location d (length len) to ctx + +/** + * @brief load the private key file into SSL context + * + * @param ctx - SSL context point + * @param file - private key file name + * @param type - private key encoding type + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); + +/** + * @brief load the RSA private key into SSL context + * + * @param ctx - SSL context point + * @param x - RSA private key point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); + +/** + * @brief load the RSA ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - RSA private key length + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); + +/** + * @brief load the RSA private key file into SSL context + * + * @param ctx - SSL context point + * @param file - RSA private key file name + * @param type - private key encoding type + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); + + +/** + * @brief check if the private key and certification is matched + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +/** + * @brief set the SSL context server information + * + * @param ctx - SSL context point + * @param serverinfo - server information string + * @param serverinfo_length - server information length + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo, size_t serverinfo_length); + +/** + * @brief load the SSL context server infomation file into SSL context + * + * @param ctx - SSL context point + * @param file - server information file + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file); + +/** + * @brief SSL select next function + * + * @param out - point of output data point + * @param outlen - output data length + * @param in - input data + * @param inlen - input data length + * @param client - client data point + * @param client_len -client data length + * + * @return NPN state + * OPENSSL_NPN_UNSUPPORTED : not support + * OPENSSL_NPN_NEGOTIATED : negotiated + * OPENSSL_NPN_NO_OVERLAP : no overlap + */ +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const unsigned char *client, unsigned int client_len); + +/** + * @brief load the extra certification chain into the SSL context + * + * @param ctx - SSL context point + * @param x509 - X509 certification + * + * @return result + * 1 : OK + * 0 : failed + */ +long SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *); + +/** + * @brief control the SSL context + * + * @param ctx - SSL context point + * @param cmd - command + * @param larg - parameter length + * @param parg - parameter point + * + * @return result + * 1 : OK + * 0 : failed + */ +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, char *parg); + +/** + * @brief get the SSL context cipher + * + * @param ctx - SSL context point + * + * @return SSL context cipher + */ +STACK *SSL_CTX_get_ciphers(const SSL_CTX *ctx); + +/** + * @brief check if the SSL context can read as many as data + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx); + +/** + * @brief get the SSL context extra data + * + * @param ctx - SSL context point + * @param idx - index + * + * @return data point + */ +char *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx); + +/** + * @brief get the SSL context quiet shutdown option + * + * @param ctx - SSL context point + * + * @return quiet shutdown option + */ +int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); + +/** + * @brief load the SSL context CA file + * + * @param ctx - SSL context point + * @param CAfile - CA certification file + * @param CApath - CA certification file path + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath); + +/** + * @brief add SSL context reference count by '1' + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_up_ref(SSL_CTX *ctx); + +/** + * @brief set SSL context application private data + * + * @param ctx - SSL context point + * @param arg - private data + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_app_data(SSL_CTX *ctx, void *arg); + +/** + * @brief set SSL context client certification callback function + * + * @param ctx - SSL context point + * @param cb - callback function + * + * @return none + */ +void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); + +/** + * @brief set the SSL context if we can read as many as data + * + * @param ctx - SSL context point + * @param m - enable the fuction + * + * @return none + */ +void SSL_CTX_set_default_read_ahead(SSL_CTX *ctx, int m); + +/** + * @brief set SSL context default verifying path + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); + +/** + * @brief set SSL context default verifying directory + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_dir(SSL_CTX *ctx); + +/** + * @brief set SSL context default verifying file + * + * @param ctx - SSL context point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_file(SSL_CTX *ctx); + +/** + * @brief set SSL context extra data + * + * @param ctx - SSL context point + * @param idx - data index + * @param arg - data point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, char *arg); + +/** + * @brief clear the SSL context option bit of "op" + * + * @param ctx - SSL context point + * @param op - option + * + * @return SSL context option + */ +unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op); + +/** + * @brief get the SSL context option + * + * @param ctx - SSL context point + * @param op - option + * + * @return SSL context option + */ +unsigned long SSL_CTX_get_options(SSL_CTX *ctx); + +/** + * @brief set the SSL context quiet shutdown mode + * + * @param ctx - SSL context point + * @param mode - mode + * + * @return none + */ +void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); + +/** + * @brief get the SSL context X509 certification + * + * @param ctx - SSL context point + * + * @return X509 certification + */ +X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); + +/** + * @brief get the SSL context private key + * + * @param ctx - SSL context point + * + * @return private key + */ +EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx); + +/** + * @brief set SSL context PSK identity hint + * + * @param ctx - SSL context point + * @param hint - PSK identity hint + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint); + +/** + * @brief set SSL context PSK server callback function + * + * @param ctx - SSL context point + * @param callback - callback function + * + * @return none + */ +void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, + unsigned int (*callback)(SSL *ssl, + const char *identity, + unsigned char *psk, + int max_psk_len)); +/** + * @brief get alert description string + * + * @param value - alert value + * + * @return alert description string + */ +const char *SSL_alert_desc_string(int value); + +/** + * @brief get alert description long string + * + * @param value - alert value + * + * @return alert description long string + */ +const char *SSL_alert_desc_string_long(int value); + +/** + * @brief get alert type string + * + * @param value - alert value + * + * @return alert type string + */ +const char *SSL_alert_type_string(int value); + +/** + * @brief get alert type long string + * + * @param value - alert value + * + * @return alert type long string + */ +const char *SSL_alert_type_string_long(int value); + +/** + * @brief get SSL context of the SSL + * + * @param ssl - SSL point + * + * @return SSL context + */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); + +/** + * @brief get SSL application data + * + * @param ssl - SSL point + * + * @return application data + */ +char *SSL_get_app_data(SSL *ssl); + +/** + * @brief get SSL cipher bits + * + * @param ssl - SSL point + * @param alg_bits - algorithm bits + * + * @return strength bits + */ +int SSL_get_cipher_bits(const SSL *ssl, int *alg_bits); + +/** + * @brief get SSL cipher name + * + * @param ssl - SSL point + * + * @return SSL cipher name + */ +char *SSL_get_cipher_name(const SSL *ssl); + +/** + * @brief get SSL cipher version + * + * @param ssl - SSL point + * + * @return SSL cipher version + */ +char *SSL_get_cipher_version(const SSL *ssl); + +/** + * @brief get SSL extra data + * + * @param ssl - SSL point + * @param idx - data index + * + * @return extra data + */ +char *SSL_get_ex_data(const SSL *ssl, int idx); + +/** + * @brief get index of the SSL extra data X509 storage context + * + * @param none + * + * @return data index + */ +int SSL_get_ex_data_X509_STORE_CTX_idx(void); + +/** + * @brief get peer certification chain + * + * @param ssl - SSL point + * + * @return certification chain + */ +STACK *SSL_get_peer_cert_chain(const SSL *ssl); + +/** + * @brief get peer certification + * + * @param ssl - SSL point + * + * @return certification + */ +X509 *SSL_get_peer_certificate(const SSL *ssl); + +/** + * @brief get SSL quiet shutdown mode + * + * @param ssl - SSL point + * + * @return quiet shutdown mode + */ +int SSL_get_quiet_shutdown(const SSL *ssl); + +/** + * @brief get SSL read only IO handle + * + * @param ssl - SSL point + * + * @return IO handle + */ +BIO *SSL_get_rbio(const SSL *ssl); + +/** + * @brief get SSL shared ciphers + * + * @param ssl - SSL point + * @param buf - buffer to store the ciphers + * @param len - buffer len + * + * @return shared ciphers + */ +char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len); + +/** + * @brief get SSL shutdown mode + * + * @param ssl - SSL point + * + * @return shutdown mode + */ +int SSL_get_shutdown(const SSL *ssl); + +/** + * @brief get SSL session time + * + * @param ssl - SSL point + * + * @return session time + */ +long SSL_get_time(const SSL *ssl); + +/** + * @brief get SSL session timeout time + * + * @param ssl - SSL point + * + * @return session timeout time + */ +long SSL_get_timeout(const SSL *ssl); + +/** + * @brief get SSL verifying mode + * + * @param ssl - SSL point + * + * @return verifying mode + */ +int SSL_get_verify_mode(const SSL *ssl); + +/** + * @brief get SSL write only IO handle + * + * @param ssl - SSL point + * + * @return IO handle + */ +BIO *SSL_get_wbio(const SSL *ssl); + +/** + * @brief load SSL client CA certification file + * + * @param file - file name + * + * @return certification loading object + */ +STACK *SSL_load_client_CA_file(const char *file); + +/** + * @brief add SSL reference by '1' + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_up_ref(SSL *ssl); + +/** + * @brief read and put data into buf, but not clear the SSL low-level storage + * + * @param ssl - SSL point + * @param buf - storage buffer point + * @param num - data bytes + * + * @return result + * > 0 : OK, and return read bytes + * = 0 : connect is closed + * < 0 : a error catch + */ +int SSL_peek(SSL *ssl, void *buf, int num); + +/** + * @brief make SSL renegotiate + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_renegotiate(SSL *ssl); + +/** + * @brief get the state string where SSL is reading + * + * @param ssl - SSL point + * + * @return state string + */ +const char *SSL_rstate_string(SSL *ssl); + +/** + * @brief get the statement long string where SSL is reading + * + * @param ssl - SSL point + * + * @return statement long string + */ +const char *SSL_rstate_string_long(SSL *ssl); + +/** + * @brief set SSL accept statement + * + * @param ssl - SSL point + * + * @return none + */ +void SSL_set_accept_state(SSL *ssl); + +/** + * @brief set SSL application data + * + * @param ssl - SSL point + * @param arg - SSL application data point + * + * @return none + */ +void SSL_set_app_data(SSL *ssl, char *arg); + +/** + * @brief set SSL BIO + * + * @param ssl - SSL point + * @param rbio - read only IO + * @param wbio - write only IO + * + * @return none + */ +void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); + +/** + * @brief clear SSL option + * + * @param ssl - SSL point + * @param op - clear option + * + * @return SSL option + */ +unsigned long SSL_clear_options(SSL *ssl, unsigned long op); + +/** + * @brief get SSL option + * + * @param ssl - SSL point + * + * @return SSL option + */ +unsigned long SSL_get_options(SSL *ssl); + +/** + * @brief clear SSL option + * + * @param ssl - SSL point + * @param op - setting option + * + * @return SSL option + */ +unsigned long SSL_set_options(SSL *ssl, unsigned long op); + +/** + * @brief set SSL quiet shutdown mode + * + * @param ssl - SSL point + * @param mode - quiet shutdown mode + * + * @return none + */ +void SSL_set_quiet_shutdown(SSL *ssl, int mode); + +/** + * @brief set SSL shutdown mode + * + * @param ssl - SSL point + * @param mode - shutdown mode + * + * @return none + */ +void SSL_set_shutdown(SSL *ssl, int mode); + +/** + * @brief set SSL session time + * + * @param ssl - SSL point + * @param t - session time + * + * @return session time + */ +void SSL_set_time(SSL *ssl, long t); + +/** + * @brief set SSL session timeout time + * + * @param ssl - SSL point + * @param t - session timeout time + * + * @return session timeout time + */ +void SSL_set_timeout(SSL *ssl, long t); + +/** + * @brief get SSL statement string + * + * @param ssl - SSL point + * + * @return SSL statement string + */ +char *SSL_state_string(const SSL *ssl); + +/** + * @brief get SSL statement long string + * + * @param ssl - SSL point + * + * @return SSL statement long string + */ +char *SSL_state_string_long(const SSL *ssl); + +/** + * @brief get SSL renegotiation count + * + * @param ssl - SSL point + * + * @return renegotiation count + */ +long SSL_total_renegotiations(SSL *ssl); + +/** + * @brief get SSL version + * + * @param ssl - SSL point + * + * @return SSL version + */ +int SSL_version(const SSL *ssl); + +/** + * @brief set SSL PSK identity hint + * + * @param ssl - SSL point + * @param hint - identity hint + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_use_psk_identity_hint(SSL *ssl, const char *hint); + +/** + * @brief get SSL PSK identity hint + * + * @param ssl - SSL point + * + * @return identity hint + */ +const char *SSL_get_psk_identity_hint(SSL *ssl); + +/** + * @brief get SSL PSK identity + * + * @param ssl - SSL point + * + * @return identity + */ +const char *SSL_get_psk_identity(SSL *ssl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/openssl/include/platform/ssl_opt.h b/components/openssl/include/platform/ssl_opt.h new file mode 100644 index 0000000000..01d438eb8a --- /dev/null +++ b/components/openssl/include/platform/ssl_opt.h @@ -0,0 +1,48 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_OPT_H_ +#define _SSL_OPT_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * if not define "ESP32_IDF_PLATFORM", system will use esp8266 platform interface + */ +#define ESP32_IDF_PLATFORM + +/** + * openssl debug print function enable + */ +#define SSL_DEBUG_ENBALE 0 + +/** + * openssl debug print function level. function whose level is lower that "SSL_DEBUG_LEVEL" + * will not print message + */ +#define SSL_DEBUG_LEVEL 0 + +/** + * openssl assert function enable, it will check the input paramter and print the message + */ +#define SSL_ASSERT_ENABLE 0 + +/** + * openssl location function enable, it will print location of the positioning error + */ +#define SSL_DEBUG_LOCATION_ENABLE 0 + +#endif diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h new file mode 100644 index 0000000000..a516d57422 --- /dev/null +++ b/components/openssl/include/platform/ssl_pm.h @@ -0,0 +1,56 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_PM_H_ +#define _SSL_PM_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ssl_types.h" +#include "ssl_port.h" + +#define LOCAL_ATRR + +int ssl_pm_new(SSL *ssl); +void ssl_pm_free(SSL *ssl); + +int ssl_pm_handshake(SSL *ssl); +int ssl_pm_shutdown(SSL *ssl); +int ssl_pm_clear(SSL *ssl); + +int ssl_pm_read(SSL *ssl, void *buffer, int len); +int ssl_pm_send(SSL *ssl, const void *buffer, int len); +int ssl_pm_pending(const SSL *ssl); + +void ssl_pm_set_fd(SSL *ssl, int fd, int mode); +int ssl_pm_get_fd(const SSL *ssl, int mode); + +OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl); + +void ssl_pm_set_bufflen(SSL *ssl, int len); + +int x509_pm_show_info(X509 *x); +int x509_pm_new(X509 *x, X509 *m_x); +void x509_pm_free(X509 *x); +int x509_pm_load(X509 *x, const unsigned char *buffer, int len); + +int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pk); +void pkey_pm_free(EVP_PKEY *pk); +int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len); + +long ssl_pm_get_verify_result(const SSL *ssl); + +#endif diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h new file mode 100644 index 0000000000..35c8dc18f9 --- /dev/null +++ b/components/openssl/include/platform/ssl_port.h @@ -0,0 +1,49 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 _SSL_PORT_H_ +#define _SSL_PORT_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "platform/ssl_opt.h" + +#ifdef ESP32_IDF_PLATFORM + +#include "esp_types.h" +#include "esp_log.h" + +void *ssl_mem_zalloc(size_t size); +void *ssl_mem_malloc(size_t size); +void ssl_mem_free(void *p); + +void* ssl_memcpy(void *to, const void *from, size_t size); +size_t ssl_strlen(const char *src); + +void ssl_speed_up_enter(void); +void ssl_speed_up_exit(void); + +#define SSL_PRINT_LOG(fmt, ...) ESP_LOGD("openssl", fmt, ##__VA_ARGS__) +#define SSL_ERROR_LOG(fmt, ...) ESP_LOGE("openssl", fmt, ##__VA_ARGS__) +#define SSL_LOCAL_LOG(fmt, ...) ESP_LOGD("openssl", fmt, ##__VA_ARGS__) + +#elif defined(SSL_PLATFORM_USER_INCLUDE) + +SSL_PLATFORM_USER_INCLUDE + +#endif + +#endif diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c new file mode 100644 index 0000000000..0193a441e0 --- /dev/null +++ b/components/openssl/library/ssl_cert.c @@ -0,0 +1,79 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "ssl_cert.h" +#include "ssl_pkey.h" +#include "ssl_x509.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +/** + * @brief create a certification object according to input certification + */ +CERT *__ssl_cert_new(CERT *ic) +{ + CERT *cert; + + X509 *ix; + EVP_PKEY *ipk; + + cert = ssl_mem_zalloc(sizeof(CERT)); + if (!cert) + SSL_RET(failed1, "ssl_mem_zalloc\n"); + + if (ic) { + ipk = ic->pkey; + ix = ic->x509; + } else { + ipk = NULL; + ix = NULL; + } + + cert->pkey = __EVP_PKEY_new(ipk); + if (!cert->pkey) + SSL_RET(failed2, "__EVP_PKEY_new\n"); + + cert->x509 = __X509_new(ix); + if (!cert->x509) + SSL_RET(failed3, "__X509_new\n"); + + return cert; + +failed3: + EVP_PKEY_free(cert->pkey); +failed2: + ssl_mem_free(cert); +failed1: + return NULL; +} + +/** + * @brief create a certification object include private key object + */ +CERT *ssl_cert_new(void) +{ + return __ssl_cert_new(NULL); +} + +/** + * @brief free a certification object + */ +void ssl_cert_free(CERT *cert) +{ + X509_free(cert->x509); + + EVP_PKEY_free(cert->pkey); + + ssl_mem_free(cert); +} diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c new file mode 100644 index 0000000000..23b8bf4cea --- /dev/null +++ b/components/openssl/library/ssl_lib.c @@ -0,0 +1,1506 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "ssl_lib.h" +#include "ssl_pkey.h" +#include "ssl_x509.h" +#include "ssl_cert.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +#define SSL_SEND_DATA_MAX_LENGTH 1460 + +/** + * @brief Discover whether the current connection is in the error state + */ +int ossl_statem_in_error(const SSL *ssl) +{ + if (ssl->statem.state == MSG_FLOW_ERROR) + return 1; + + return 0; +} + +/** + * @brief get the SSL specifical statement + */ +int SSL_want(const SSL *ssl) +{ + return ssl->rwstate; +} + +/** + * @brief check if SSL want nothing + */ +int SSL_want_nothing(const SSL *ssl) +{ + return (SSL_want(ssl) == SSL_NOTHING); +} + +/** + * @brief check if SSL want to read + */ +int SSL_want_read(const SSL *ssl) +{ + return (SSL_want(ssl) == SSL_READING); +} + +/** + * @brief check if SSL want to write + */ +int SSL_want_write(const SSL *ssl) +{ + return (SSL_want(ssl) == SSL_WRITING); +} + +/** + * @brief check if SSL want to lookup X509 certification + */ +int SSL_want_x509_lookup(const SSL *ssl) +{ + return (SSL_want(ssl) == SSL_WRITING); +} + +/** + * @brief get SSL error code + */ +int SSL_get_error(const SSL *ssl, int ret_code) +{ + int ret = SSL_ERROR_SYSCALL; + + SSL_ASSERT(ssl); + + if (ret_code > 0) + ret = SSL_ERROR_NONE; + else if (ret_code < 0) + { + if (SSL_want_read(ssl)) + ret = SSL_ERROR_WANT_READ; + else if (SSL_want_write(ssl)) + ret = SSL_ERROR_WANT_WRITE; + else + ret = SSL_ERROR_SYSCALL; //unknown + } + else // ret_code == 0 + { + if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) + ret = SSL_ERROR_ZERO_RETURN; + else + ret = SSL_ERROR_SYSCALL; + } + + return ret; +} + +/** + * @brief get the SSL state + */ +OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) +{ + OSSL_HANDSHAKE_STATE state; + + SSL_ASSERT(ssl); + + state = SSL_METHOD_CALL(get_state, ssl); + + return state; +} + +/** + * @brief create a new SSL session object + */ +SSL_SESSION* SSL_SESSION_new(void) +{ + SSL_SESSION *session; + + session = ssl_mem_zalloc(sizeof(SSL_SESSION)); + if (!session) + SSL_RET(failed1, "ssl_mem_zalloc\n"); + + session->peer = X509_new(); + if (!session->peer) + SSL_RET(failed2, "X509_new\n"); + + return session; + +failed2: + ssl_mem_free(session); +failed1: + return NULL; +} + +/** + * @brief free a new SSL session object + */ +void SSL_SESSION_free(SSL_SESSION *session) +{ + X509_free(session->peer); + ssl_mem_free(session); +} + +/** + * @brief create a SSL context + */ +SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) +{ + SSL_CTX *ctx; + CERT *cert; + X509 *client_ca; + + if (!method) SSL_RET(go_failed1, "method:NULL\n"); + + client_ca = X509_new(); + if (!client_ca) + SSL_RET(go_failed1, "X509_new\n"); + + cert = ssl_cert_new(); + if (!cert) + SSL_RET(go_failed2, "ssl_cert_new\n"); + + ctx = (SSL_CTX *)ssl_mem_zalloc(sizeof(SSL_CTX)); + if (!ctx) + SSL_RET(go_failed3, "ssl_mem_zalloc:ctx\n"); + + ctx->method = method; + ctx->client_CA = client_ca; + ctx->cert = cert; + + ctx->version = method->version; + + return ctx; + +go_failed3: + ssl_cert_free(cert); +go_failed2: + X509_free(client_ca); +go_failed1: + return NULL; +} + +/** + * @brief free a SSL context + */ +void SSL_CTX_free(SSL_CTX* ctx) +{ + SSL_ASSERT(ctx); + + ssl_cert_free(ctx->cert); + + X509_free(ctx->client_CA); + + ssl_mem_free(ctx); +} + +/** + * @brief set the SSL context version + */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(meth); + + ctx->method = meth; + + ctx->version = meth->version; + + return 1; +} + +/** + * @brief get the SSL context current method + */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->method; +} + +/** + * @brief create a SSL + */ +SSL *SSL_new(SSL_CTX *ctx) +{ + int ret = 0; + SSL *ssl; + + if (!ctx) + SSL_RET(failed1, "ctx:NULL\n"); + + ssl = (SSL *)ssl_mem_zalloc(sizeof(SSL)); + if (!ssl) + SSL_RET(failed1, "ssl_mem_zalloc\n"); + + ssl->session = SSL_SESSION_new(); + if (!ssl->session) + SSL_RET(failed2, "SSL_SESSION_new\n"); + + ssl->cert = __ssl_cert_new(ctx->cert); + if (!ssl->cert) + SSL_RET(failed3, "__ssl_cert_new\n"); + + ssl->client_CA = __X509_new(ctx->client_CA); + if (!ssl->client_CA) + SSL_RET(failed4, "__X509_new\n"); + + ssl->ctx = ctx; + ssl->method = ctx->method; + + ssl->version = ctx->version; + ssl->options = ctx->options; + + ssl->verify_mode = ctx->verify_mode; + + ret = SSL_METHOD_CALL(new, ssl); + if (ret) + SSL_RET(failed5, "ssl_new\n"); + + ssl->rwstate = SSL_NOTHING; + + return ssl; + +failed5: + X509_free(ssl->client_CA); +failed4: + ssl_cert_free(ssl->cert); +failed3: + SSL_SESSION_free(ssl->session); +failed2: + ssl_mem_free(ssl); +failed1: + return NULL; +} + +/** + * @brief free the SSL + */ +void SSL_free(SSL *ssl) +{ + SSL_ASSERT(ssl); + + SSL_METHOD_CALL(free, ssl); + + X509_free(ssl->client_CA); + + ssl_cert_free(ssl->cert); + + SSL_SESSION_free(ssl->session); + + ssl_mem_free(ssl); +} + +/** + * @brief perform the SSL handshake + */ +int SSL_do_handshake(SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = SSL_METHOD_CALL(handshake, ssl); + + return ret; +} + +/** + * @brief connect to the remote SSL server + */ +int SSL_connect(SSL *ssl) +{ + SSL_ASSERT(ssl); + + return SSL_do_handshake(ssl); +} + +/** + * @brief accept the remote connection + */ +int SSL_accept(SSL *ssl) +{ + SSL_ASSERT(ssl); + + return SSL_do_handshake(ssl); +} + +/** + * @brief shutdown the connection + */ +int SSL_shutdown(SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + if (SSL_get_state(ssl) != TLS_ST_OK) return 1; + + ret = SSL_METHOD_CALL(shutdown, ssl); + + return ret; +} + +/** + * @brief reset the SSL + */ +int SSL_clear(SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = SSL_shutdown(ssl); + if (1 != ret) + SSL_ERR(0, go_failed1, "SSL_shutdown\n"); + + SSL_METHOD_CALL(free, ssl); + + ret = SSL_METHOD_CALL(new, ssl); + if (!ret) + SSL_ERR(0, go_failed1, "ssl_new\n"); + + return 1; + +go_failed1: + return ret; +} + +/** + * @brief read data from to remote + */ +int SSL_read(SSL *ssl, void *buffer, int len) +{ + int ret; + + SSL_ASSERT(ssl); + SSL_ASSERT(buffer); + SSL_ASSERT(len); + + ssl->rwstate = SSL_READING; + + ret = SSL_METHOD_CALL(read, ssl, buffer, len); + + if (ret == len) + ssl->rwstate = SSL_NOTHING; + + return ret; +} + +/** + * @brief send the data to remote + */ +int SSL_write(SSL *ssl, const void *buffer, int len) +{ + int ret; + int send_bytes; + const unsigned char *pbuf; + + SSL_ASSERT(ssl); + SSL_ASSERT(buffer); + SSL_ASSERT(len); + + ssl->rwstate = SSL_WRITING; + + send_bytes = len; + pbuf = (const unsigned char *)buffer; + + do { + int bytes; + + if (send_bytes > SSL_SEND_DATA_MAX_LENGTH) + bytes = SSL_SEND_DATA_MAX_LENGTH; + else + bytes = send_bytes; + + ret = SSL_METHOD_CALL(send, ssl, buffer, bytes); + if (ret > 0) { + pbuf += ret; + send_bytes -= ret; + } + } while (ret > 0 && send_bytes); + + if (ret >= 0) { + ret = len - send_bytes; + ssl->rwstate = SSL_NOTHING; + } else + ret = -1; + + return ret; +} + +/** + * @brief get SSL context of the SSL + */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->ctx; +} + +/** + * @brief get the SSL current method + */ +const SSL_METHOD *SSL_get_ssl_method(SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->method; +} + +/** + * @brief set the SSL method + */ +int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method) +{ + int ret; + + SSL_ASSERT(ssl); + SSL_ASSERT(method); + + if (ssl->version != method->version) { + + ret = SSL_shutdown(ssl); + if (1 != ret) + SSL_ERR(0, go_failed1, "SSL_shutdown\n"); + + SSL_METHOD_CALL(free, ssl); + + ssl->method = method; + + ret = SSL_METHOD_CALL(new, ssl); + if (!ret) + SSL_ERR(0, go_failed1, "ssl_new\n"); + } else { + ssl->method = method; + } + + + return 1; + +go_failed1: + return ret; +} + +/** + * @brief get SSL shutdown mode + */ +int SSL_get_shutdown(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->shutdown; +} + +/** + * @brief set SSL shutdown mode + */ +void SSL_set_shutdown(SSL *ssl, int mode) +{ + SSL_ASSERT(ssl); + + ssl->shutdown = mode; +} + + +/** + * @brief get the number of the bytes to be read + */ +int SSL_pending(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = SSL_METHOD_CALL(pending, ssl); + + return ret; +} + +/** + * @brief check if some data can be read + */ +int SSL_has_pending(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + if (SSL_pending(ssl)) + ret = 1; + else + ret = 0; + + return ret; +} + +/** + * @brief clear the SSL context option bit of "op" + */ +unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op) +{ + return ctx->options &= ~op; +} + +/** + * @brief get the SSL context option + */ +unsigned long SSL_CTX_get_options(SSL_CTX *ctx) +{ + return ctx->options; +} + +/** + * @brief set the option of the SSL context + */ +unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt) +{ + return ctx->options |= opt; +} + +/** + * @brief clear SSL option + */ +unsigned long SSL_clear_options(SSL *ssl, unsigned long op) +{ + SSL_ASSERT(ssl); + + return ssl->options & ~op; +} + +/** + * @brief get SSL option + */ +unsigned long SSL_get_options(SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->options; +} + +/** + * @brief clear SSL option + */ +unsigned long SSL_set_options(SSL *ssl, unsigned long op) +{ + SSL_ASSERT(ssl); + + return ssl->options |= op; +} + +/** + * @brief get the socket handle of the SSL + */ +int SSL_get_fd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = SSL_METHOD_CALL(get_fd, ssl, 0); + + return ret; +} + +/** + * @brief get the read only socket handle of the SSL + */ +int SSL_get_rfd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = SSL_METHOD_CALL(get_fd, ssl, 0); + + return ret; +} + +/** + * @brief get the write only socket handle of the SSL + */ +int SSL_get_wfd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = SSL_METHOD_CALL(get_fd, ssl, 0); + + return ret; +} + +/** + * @brief bind the socket file description into the SSL + */ +int SSL_set_fd(SSL *ssl, int fd) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(fd >= 0); + + SSL_METHOD_CALL(set_fd, ssl, fd, 0); + + return 1; +} + +/** + * @brief bind the read only socket file description into the SSL + */ +int SSL_set_rfd(SSL *ssl, int fd) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(fd >= 0); + + SSL_METHOD_CALL(set_fd, ssl, fd, 0); + + return 1; +} + +/** + * @brief bind the write only socket file description into the SSL + */ +int SSL_set_wfd(SSL *ssl, int fd) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(fd >= 0); + + SSL_METHOD_CALL(set_fd, ssl, fd, 0); + + return 1; +} + +/** + * @brief get SSL version + */ +int SSL_version(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->version; +} + +/** + * @brief get the SSL version string + */ +static const char* ssl_protocol_to_string(int version) +{ + const char *str; + + if (version == TLS1_2_VERSION) + str = "TLSv1.2"; + else if (version == TLS1_1_VERSION) + str = "TLSv1.1"; + else if (version == TLS1_VERSION) + str = "TLSv1"; + else if (version == SSL3_VERSION) + str = "SSLv3"; + else + str = "unknown"; + + return str; +} + +/** + * @brief get the SSL current version + */ +const char *SSL_get_version(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl_protocol_to_string(SSL_version(ssl)); +} + +/** + * @brief get alert description string + */ +const char* SSL_alert_desc_string(int value) +{ + const char *str; + + switch (value & 0xff) + { + case SSL3_AD_CLOSE_NOTIFY: + str = "CN"; + break; + case SSL3_AD_UNEXPECTED_MESSAGE: + str = "UM"; + break; + case SSL3_AD_BAD_RECORD_MAC: + str = "BM"; + break; + case SSL3_AD_DECOMPRESSION_FAILURE: + str = "DF"; + break; + case SSL3_AD_HANDSHAKE_FAILURE: + str = "HF"; + break; + case SSL3_AD_NO_CERTIFICATE: + str = "NC"; + break; + case SSL3_AD_BAD_CERTIFICATE: + str = "BC"; + break; + case SSL3_AD_UNSUPPORTED_CERTIFICATE: + str = "UC"; + break; + case SSL3_AD_CERTIFICATE_REVOKED: + str = "CR"; + break; + case SSL3_AD_CERTIFICATE_EXPIRED: + str = "CE"; + break; + case SSL3_AD_CERTIFICATE_UNKNOWN: + str = "CU"; + break; + case SSL3_AD_ILLEGAL_PARAMETER: + str = "IP"; + break; + case TLS1_AD_DECRYPTION_FAILED: + str = "DC"; + break; + case TLS1_AD_RECORD_OVERFLOW: + str = "RO"; + break; + case TLS1_AD_UNKNOWN_CA: + str = "CA"; + break; + case TLS1_AD_ACCESS_DENIED: + str = "AD"; + break; + case TLS1_AD_DECODE_ERROR: + str = "DE"; + break; + case TLS1_AD_DECRYPT_ERROR: + str = "CY"; + break; + case TLS1_AD_EXPORT_RESTRICTION: + str = "ER"; + break; + case TLS1_AD_PROTOCOL_VERSION: + str = "PV"; + break; + case TLS1_AD_INSUFFICIENT_SECURITY: + str = "IS"; + break; + case TLS1_AD_INTERNAL_ERROR: + str = "IE"; + break; + case TLS1_AD_USER_CANCELLED: + str = "US"; + break; + case TLS1_AD_NO_RENEGOTIATION: + str = "NR"; + break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str = "UE"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str = "CO"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str = "UN"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str = "BR"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str = "BH"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str = "UP"; + break; + default: + str = "UK"; + break; + } + + return str; +} + +/** + * @brief get alert description long string + */ +const char* SSL_alert_desc_string_long(int value) +{ + const char *str; + + switch (value & 0xff) + { + case SSL3_AD_CLOSE_NOTIFY: + str = "close notify"; + break; + case SSL3_AD_UNEXPECTED_MESSAGE: + str = "unexpected_message"; + break; + case SSL3_AD_BAD_RECORD_MAC: + str = "bad record mac"; + break; + case SSL3_AD_DECOMPRESSION_FAILURE: + str = "decompression failure"; + break; + case SSL3_AD_HANDSHAKE_FAILURE: + str = "handshake failure"; + break; + case SSL3_AD_NO_CERTIFICATE: + str = "no certificate"; + break; + case SSL3_AD_BAD_CERTIFICATE: + str = "bad certificate"; + break; + case SSL3_AD_UNSUPPORTED_CERTIFICATE: + str = "unsupported certificate"; + break; + case SSL3_AD_CERTIFICATE_REVOKED: + str = "certificate revoked"; + break; + case SSL3_AD_CERTIFICATE_EXPIRED: + str = "certificate expired"; + break; + case SSL3_AD_CERTIFICATE_UNKNOWN: + str = "certificate unknown"; + break; + case SSL3_AD_ILLEGAL_PARAMETER: + str = "illegal parameter"; + break; + case TLS1_AD_DECRYPTION_FAILED: + str = "decryption failed"; + break; + case TLS1_AD_RECORD_OVERFLOW: + str = "record overflow"; + break; + case TLS1_AD_UNKNOWN_CA: + str = "unknown CA"; + break; + case TLS1_AD_ACCESS_DENIED: + str = "access denied"; + break; + case TLS1_AD_DECODE_ERROR: + str = "decode error"; + break; + case TLS1_AD_DECRYPT_ERROR: + str = "decrypt error"; + break; + case TLS1_AD_EXPORT_RESTRICTION: + str = "export restriction"; + break; + case TLS1_AD_PROTOCOL_VERSION: + str = "protocol version"; + break; + case TLS1_AD_INSUFFICIENT_SECURITY: + str = "insufficient security"; + break; + case TLS1_AD_INTERNAL_ERROR: + str = "internal error"; + break; + case TLS1_AD_USER_CANCELLED: + str = "user canceled"; + break; + case TLS1_AD_NO_RENEGOTIATION: + str = "no renegotiation"; + break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str = "unsupported extension"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str = "certificate unobtainable"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str = "unrecognized name"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str = "bad certificate status response"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str = "bad certificate hash value"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str = "unknown PSK identity"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/** + * @brief get alert type string + */ +const char *SSL_alert_type_string(int value) +{ + const char *str; + + switch (value >> 8) + { + case SSL3_AL_WARNING: + str = "W"; + break; + case SSL3_AL_FATAL: + str = "F"; + break; + default: + str = "U"; + break; + } + + return str; +} + +/** + * @brief get alert type long string + */ +const char *SSL_alert_type_string_long(int value) +{ + const char *str; + + switch (value >> 8) + { + case SSL3_AL_WARNING: + str = "warning"; + break; + case SSL3_AL_FATAL: + str = "fatal"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/** + * @brief get the state string where SSL is reading + */ +const char *SSL_rstate_string(SSL *ssl) +{ + const char *str; + + SSL_ASSERT(ssl); + + switch (ssl->rlayer.rstate) + { + case SSL_ST_READ_HEADER: + str = "RH"; + break; + case SSL_ST_READ_BODY: + str = "RB"; + break; + case SSL_ST_READ_DONE: + str = "RD"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/** + * @brief get the statement long string where SSL is reading + */ +const char *SSL_rstate_string_long(SSL *ssl) +{ + const char *str = "unknown"; + + SSL_ASSERT(ssl); + + switch (ssl->rlayer.rstate) + { + case SSL_ST_READ_HEADER: + str = "read header"; + break; + case SSL_ST_READ_BODY: + str = "read body"; + break; + case SSL_ST_READ_DONE: + str = "read done"; + break; + default: + break; + } + + return str; +} + +/** + * @brief get SSL statement string + */ +char *SSL_state_string(const SSL *ssl) +{ + char *str = "UNKWN "; + + SSL_ASSERT(ssl); + + if (ossl_statem_in_error(ssl)) + str = "SSLERR"; + else + { + switch (SSL_get_state(ssl)) + { + case TLS_ST_BEFORE: + str = "PINIT "; + break; + case TLS_ST_OK: + str = "SSLOK "; + break; + case TLS_ST_CW_CLNT_HELLO: + str = "TWCH"; + break; + case TLS_ST_CR_SRVR_HELLO: + str = "TRSH"; + break; + case TLS_ST_CR_CERT: + str = "TRSC"; + break; + case TLS_ST_CR_KEY_EXCH: + str = "TRSKE"; + break; + case TLS_ST_CR_CERT_REQ: + str = "TRCR"; + break; + case TLS_ST_CR_SRVR_DONE: + str = "TRSD"; + break; + case TLS_ST_CW_CERT: + str = "TWCC"; + break; + case TLS_ST_CW_KEY_EXCH: + str = "TWCKE"; + break; + case TLS_ST_CW_CERT_VRFY: + str = "TWCV"; + break; + case TLS_ST_SW_CHANGE: + case TLS_ST_CW_CHANGE: + str = "TWCCS"; + break; + case TLS_ST_SW_FINISHED: + case TLS_ST_CW_FINISHED: + str = "TWFIN"; + break; + case TLS_ST_SR_CHANGE: + case TLS_ST_CR_CHANGE: + str = "TRCCS"; + break; + case TLS_ST_SR_FINISHED: + case TLS_ST_CR_FINISHED: + str = "TRFIN"; + break; + case TLS_ST_SW_HELLO_REQ: + str = "TWHR"; + break; + case TLS_ST_SR_CLNT_HELLO: + str = "TRCH"; + break; + case TLS_ST_SW_SRVR_HELLO: + str = "TWSH"; + break; + case TLS_ST_SW_CERT: + str = "TWSC"; + break; + case TLS_ST_SW_KEY_EXCH: + str = "TWSKE"; + break; + case TLS_ST_SW_CERT_REQ: + str = "TWCR"; + break; + case TLS_ST_SW_SRVR_DONE: + str = "TWSD"; + break; + case TLS_ST_SR_CERT: + str = "TRCC"; + break; + case TLS_ST_SR_KEY_EXCH: + str = "TRCKE"; + break; + case TLS_ST_SR_CERT_VRFY: + str = "TRCV"; + break; + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + str = "DRCHV"; + break; + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + str = "DWCHV"; + break; + default: + break; + } + } + + return str; +} + +/** + * @brief get SSL statement long string + */ +char *SSL_state_string_long(const SSL *ssl) +{ + char *str = "UNKWN "; + + SSL_ASSERT(ssl); + + if (ossl_statem_in_error(ssl)) + str = "SSLERR"; + else + { + switch (SSL_get_state(ssl)) + { + case TLS_ST_BEFORE: + str = "before SSL initialization"; + break; + case TLS_ST_OK: + str = "SSL negotiation finished successfully"; + break; + case TLS_ST_CW_CLNT_HELLO: + str = "SSLv3/TLS write client hello"; + break; + case TLS_ST_CR_SRVR_HELLO: + str = "SSLv3/TLS read server hello"; + break; + case TLS_ST_CR_CERT: + str = "SSLv3/TLS read server certificate"; + break; + case TLS_ST_CR_KEY_EXCH: + str = "SSLv3/TLS read server key exchange"; + break; + case TLS_ST_CR_CERT_REQ: + str = "SSLv3/TLS read server certificate request"; + break; + case TLS_ST_CR_SESSION_TICKET: + str = "SSLv3/TLS read server session ticket"; + break; + case TLS_ST_CR_SRVR_DONE: + str = "SSLv3/TLS read server done"; + break; + case TLS_ST_CW_CERT: + str = "SSLv3/TLS write client certificate"; + break; + case TLS_ST_CW_KEY_EXCH: + str = "SSLv3/TLS write client key exchange"; + break; + case TLS_ST_CW_CERT_VRFY: + str = "SSLv3/TLS write certificate verify"; + break; + case TLS_ST_CW_CHANGE: + case TLS_ST_SW_CHANGE: + str = "SSLv3/TLS write change cipher spec"; + break; + case TLS_ST_CW_FINISHED: + case TLS_ST_SW_FINISHED: + str = "SSLv3/TLS write finished"; + break; + case TLS_ST_CR_CHANGE: + case TLS_ST_SR_CHANGE: + str = "SSLv3/TLS read change cipher spec"; + break; + case TLS_ST_CR_FINISHED: + case TLS_ST_SR_FINISHED: + str = "SSLv3/TLS read finished"; + break; + case TLS_ST_SR_CLNT_HELLO: + str = "SSLv3/TLS read client hello"; + break; + case TLS_ST_SW_HELLO_REQ: + str = "SSLv3/TLS write hello request"; + break; + case TLS_ST_SW_SRVR_HELLO: + str = "SSLv3/TLS write server hello"; + break; + case TLS_ST_SW_CERT: + str = "SSLv3/TLS write certificate"; + break; + case TLS_ST_SW_KEY_EXCH: + str = "SSLv3/TLS write key exchange"; + break; + case TLS_ST_SW_CERT_REQ: + str = "SSLv3/TLS write certificate request"; + break; + case TLS_ST_SW_SESSION_TICKET: + str = "SSLv3/TLS write session ticket"; + break; + case TLS_ST_SW_SRVR_DONE: + str = "SSLv3/TLS write server done"; + break; + case TLS_ST_SR_CERT: + str = "SSLv3/TLS read client certificate"; + break; + case TLS_ST_SR_KEY_EXCH: + str = "SSLv3/TLS read client key exchange"; + break; + case TLS_ST_SR_CERT_VRFY: + str = "SSLv3/TLS read certificate verify"; + break; + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + str = "DTLS1 read hello verify request"; + break; + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + str = "DTLS1 write hello verify request"; + break; + default: + break; + } + } + + return str; +} + +/** + * @brief set the SSL context read buffer length + */ +void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(len); + + ctx->read_buffer_len = len; +} + +/** + * @brief set the SSL read buffer length + */ +void SSL_set_default_read_buffer_len(SSL *ssl, size_t len) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(len); + + SSL_METHOD_CALL(set_bufflen, ssl, len); +} + +/** + * @brief set the SSL information callback function + */ +void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)) +{ + SSL_ASSERT(ssl); + + ssl->info_callback = cb; +} + +/** + * @brief add SSL context reference count by '1' + */ +int SSL_CTX_up_ref(SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + /** + * no support multi-thread SSL here + */ + ctx->references++; + + return 1; +} + +/** + * @brief set the SSL security level + */ +void SSL_set_security_level(SSL *ssl, int level) +{ + SSL_ASSERT(ssl); + + ssl->cert->sec_level = level; +} + +/** + * @brief get the SSL security level + */ +int SSL_get_security_level(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->cert->sec_level; +} + +/** + * @brief get the SSL verifying mode of the SSL context + */ +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->verify_mode; +} + +/** + * @brief set the session timeout time + */ +long SSL_CTX_set_timeout(SSL_CTX *ctx, long t) +{ + long l; + + SSL_ASSERT(ctx); + + l = ctx->session_timeout; + ctx->session_timeout = t; + + return l; +} + +/** + * @brief get the session timeout time + */ +long SSL_CTX_get_timeout(const SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->session_timeout; +} + +/** + * @brief set the SSL if we can read as many as data + */ +void SSL_set_read_ahead(SSL *ssl, int yes) +{ + SSL_ASSERT(ssl); + + ssl->rlayer.read_ahead = yes; +} + +/** + * @brief set the SSL context if we can read as many as data + */ +void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) +{ + SSL_ASSERT(ctx); + + ctx->read_ahead = yes; +} + +/** + * @brief get the SSL ahead signal if we can read as many as data + */ +int SSL_get_read_ahead(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->rlayer.read_ahead; +} + +/** + * @brief get the SSL context ahead signal if we can read as many as data + */ +long SSL_CTX_get_read_ahead(SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->read_ahead; +} + +/** + * @brief check if the SSL context can read as many as data + */ +long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->read_ahead; +} + +/** + * @brief set SSL session time + */ +long SSL_set_time(SSL *ssl, long t) +{ + SSL_ASSERT(ssl); + + ssl->session->time = t; + + return t; +} + +/** + * @brief set SSL session timeout time + */ +long SSL_set_timeout(SSL *ssl, long t) +{ + SSL_ASSERT(ssl); + + ssl->session->timeout = t; + + return t; +} + +/** + * @brief get the verifying result of the SSL certification + */ +long SSL_get_verify_result(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return SSL_METHOD_CALL(get_verify_result, ssl); +} + +/** + * @brief get the SSL verifying depth of the SSL context + */ +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->param.depth; +} + +/** + * @brief set the SSL verify depth of the SSL context + */ +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) +{ + SSL_ASSERT(ctx); + + ctx->param.depth = depth; +} + +/** + * @brief get the SSL verifying depth of the SSL + */ +int SSL_get_verify_depth(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->param.depth; +} + +/** + * @brief set the SSL verify depth of the SSL + */ +void SSL_set_verify_depth(SSL *ssl, int depth) +{ + SSL_ASSERT(ssl); + + ssl->param.depth = depth; +} + +/** + * @brief set the SSL context verifying of the SSL context + */ +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) +{ + SSL_ASSERT(ctx); + + ctx->verify_mode = mode; + ctx->default_verify_callback = verify_callback; +} + +/** + * @brief set the SSL verifying of the SSL context + */ +void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) +{ + SSL_ASSERT(ssl); + + ssl->verify_mode = mode; + ssl->verify_callback = verify_callback; +} diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c new file mode 100644 index 0000000000..0002360846 --- /dev/null +++ b/components/openssl/library/ssl_methods.c @@ -0,0 +1,81 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "ssl_methods.h" +#include "ssl_pm.h" + +/** + * TLS method function collection + */ +IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, + ssl_pm_new, ssl_pm_free, + ssl_pm_handshake, ssl_pm_shutdown, ssl_pm_clear, + ssl_pm_read, ssl_pm_send, ssl_pm_pending, + ssl_pm_set_fd, ssl_pm_get_fd, + ssl_pm_set_bufflen, + ssl_pm_get_verify_result, + ssl_pm_get_state); + +/** + * TLS or SSL client method collection + */ +IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 0, TLS_method_func, TLS_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 0, TLS_method_func, TLSv1_2_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 0, TLS_method_func, TLSv1_1_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_client_method); + +IMPLEMENT_SSL_METHOD(SSL3_VERSION, 0, TLS_method_func, SSLv3_client_method); + +/** + * TLS or SSL server method collection + */ +IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 1, TLS_method_func, TLS_server_method); + +IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 1, TLS_method_func, TLSv1_1_server_method); + +IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 1, TLS_method_func, TLSv1_2_server_method); + +IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_server_method); + +IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method); + +/** + * TLS or SSL method collection + */ +IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, -1, TLS_method_func, TLS_method); + +IMPLEMENT_SSL_METHOD(TLS1_2_VERSION, -1, TLS_method_func, TLSv1_2_method); + +IMPLEMENT_SSL_METHOD(TLS1_1_VERSION, -1, TLS_method_func, TLSv1_1_method); + +IMPLEMENT_SSL_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method); + +IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method); + +/** + * @brief get X509 object method + */ +IMPLEMENT_X509_METHOD(X509_method, + x509_pm_new, x509_pm_free, + x509_pm_load, x509_pm_show_info); + +/** + * @brief get private key object method + */ +IMPLEMENT_PKEY_METHOD(EVP_PKEY_method, + pkey_pm_new, pkey_pm_free, + pkey_pm_load); diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c new file mode 100644 index 0000000000..dbd82dc9c2 --- /dev/null +++ b/components/openssl/library/ssl_pkey.c @@ -0,0 +1,220 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "ssl_pkey.h" +#include "ssl_methods.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +/** + * @brief create a private key object according to input private key + */ +EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk) +{ + int ret; + EVP_PKEY *pkey; + + pkey = ssl_mem_zalloc(sizeof(EVP_PKEY)); + if (!pkey) + SSL_RET(failed1, "ssl_mem_zalloc\n"); + + if (ipk) { + pkey->method = ipk->method; + } else { + pkey->method = EVP_PKEY_method(); + } + + ret = EVP_PKEY_METHOD_CALL(new, pkey, ipk); + if (ret) + SSL_RET(failed2, "EVP_PKEY_METHOD_CALL\n"); + + return pkey; + +failed2: + ssl_mem_free(pkey); +failed1: + return NULL; +} + +/** + * @brief create a private key object + */ +EVP_PKEY* EVP_PKEY_new(void) +{ + return __EVP_PKEY_new(NULL); +} + +/** + * @brief free a private key object + */ +void EVP_PKEY_free(EVP_PKEY *pkey) +{ + EVP_PKEY_METHOD_CALL(free, pkey); + + ssl_mem_free(pkey); +} + +/** + * @brief load a character key context into system context. If '*a' is pointed to the + * private key, then load key into it. Or create a new private key object + */ +EVP_PKEY *d2i_PrivateKey(int type, + EVP_PKEY **a, + const unsigned char **pp, + long length) +{ + int m = 0; + int ret; + EVP_PKEY *pkey; + + SSL_ASSERT(pp); + SSL_ASSERT(*pp); + SSL_ASSERT(length); + + if (a && *a) { + pkey = *a; + } else { + pkey = EVP_PKEY_new();; + if (!pkey) + SSL_RET(failed1, "EVP_PKEY_new\n"); + m = 1; + } + + ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, length); + if (ret) + SSL_RET(failed2, "EVP_PKEY_METHOD_CALL\n"); + + if (a) + *a = pkey; + + return pkey; + +failed2: + if (m) + EVP_PKEY_free(pkey); +failed1: + return NULL; +} + +/** + * @brief set the SSL context private key + */ +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(pkey); + + if (ctx->cert->pkey == pkey) + return 1; + + if (ctx->cert->pkey) + EVP_PKEY_free(ctx->cert->pkey); + + ctx->cert->pkey = pkey; + + return 1; +} + +/** + * @brief set the SSL private key + */ +int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(pkey); + + if (ssl->cert->pkey == pkey) + return 1; + + if (ssl->cert->pkey) + EVP_PKEY_free(ssl->cert->pkey); + + ssl->cert->pkey = pkey; + + return 1; +} + +/** + * @brief load private key into the SSL context + */ +int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, + const unsigned char *d, long len) +{ + int ret; + EVP_PKEY *pk; + + pk = d2i_PrivateKey(0, NULL, &d, len); + if (!pk) + SSL_RET(failed1, "d2i_PrivateKey\n"); + + ret = SSL_CTX_use_PrivateKey(ctx, pk); + if (!ret) + SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); + + return 1; + +failed2: + EVP_PKEY_free(pk); +failed1: + return 0; +} + +/** + * @brief load private key into the SSL + */ +int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, + const unsigned char *d, long len) +{ + int ret; + EVP_PKEY *pk; + + pk = d2i_PrivateKey(0, NULL, &d, len); + if (!pk) + SSL_RET(failed1, "d2i_PrivateKey\n"); + + ret = SSL_use_PrivateKey(ssl, pk); + if (!ret) + SSL_RET(failed2, "SSL_use_PrivateKey\n"); + + return 1; + +failed2: + EVP_PKEY_free(pk); +failed1: + return 0; +} + +/** + * @brief load the private key file into SSL context + */ +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} + +/** + * @brief load the private key file into SSL + */ +int SSL_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} + +/** + * @brief load the RSA ASN1 private key into SSL context + */ +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len) +{ + return SSL_CTX_use_PrivateKey_ASN1(0, ctx, d, len); +} diff --git a/components/openssl/library/ssl_stack.c b/components/openssl/library/ssl_stack.c new file mode 100644 index 0000000000..5dbb69af9d --- /dev/null +++ b/components/openssl/library/ssl_stack.c @@ -0,0 +1,70 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "ssl_stack.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +#ifndef CONFIG_MIN_NODES + #define MIN_NODES 4 +#else + #define MIN_NODES CONFIG_MIN_NODES +#endif + +/** + * @brief create a openssl stack object + */ +OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) +{ + OPENSSL_STACK *stack; + char **data; + + stack = ssl_mem_zalloc(sizeof(OPENSSL_STACK)); + if (!stack) + SSL_RET(failed1, "ssl_mem_zalloc\n"); + + data = ssl_mem_zalloc(sizeof(*data) * MIN_NODES); + if (!data) + SSL_RET(failed2, "ssl_mem_zalloc\n"); + + stack->data = data; + stack->num_alloc = MIN_NODES; + stack->c = c; + + return stack; + +failed2: + ssl_mem_free(stack); +failed1: + return NULL; +} + +/** + * @brief create a NULL function openssl stack object + */ +OPENSSL_STACK *OPENSSL_sk_new_null(void) +{ + return OPENSSL_sk_new((OPENSSL_sk_compfunc)NULL); +} + +/** + * @brief free openssl stack object + */ +void OPENSSL_sk_free(OPENSSL_STACK *stack) +{ + SSL_ASSERT(stack); + + ssl_mem_free(stack->data); + ssl_mem_free(stack); +} diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c new file mode 100644 index 0000000000..d0426db18c --- /dev/null +++ b/components/openssl/library/ssl_x509.c @@ -0,0 +1,267 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "ssl_x509.h" +#include "ssl_methods.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +/** + * @brief show X509 certification information + */ +int __X509_show_info(X509 *x) +{ + return X509_METHOD_CALL(show_info, x); +} + +/** + * @brief create a X509 certification object according to input X509 certification + */ +X509* __X509_new(X509 *ix) +{ + int ret; + X509 *x; + + x = ssl_mem_zalloc(sizeof(X509)); + if (!x) + SSL_RET(failed1, "ssl_mem_zalloc\n"); + + if (ix) + x->method = ix->method; + else + x->method = X509_method(); + + ret = X509_METHOD_CALL(new, x, ix); + if (ret) + SSL_RET(failed2, "x509_new\n"); + + return x; + +failed2: + ssl_mem_free(x); +failed1: + return NULL; +} + +/** + * @brief create a X509 certification object + */ +X509* X509_new(void) +{ + return __X509_new(NULL); +} + +/** + * @brief free a X509 certification object + */ +void X509_free(X509 *x) +{ + X509_METHOD_CALL(free, x); + + ssl_mem_free(x); +}; + +/** + * @brief load a character certification context into system context. If '*cert' is pointed to the + * certification, then load certification into it. Or create a new X509 certification object + */ +X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) +{ + int m = 0; + int ret; + X509 *x; + + SSL_ASSERT(buffer); + SSL_ASSERT(len); + + if (cert && *cert) { + x = *cert; + } else { + x = X509_new(); + if (!x) + SSL_RET(failed1, "X509_new\n"); + m = 1; + } + + ret = X509_METHOD_CALL(load, x, buffer, len); + if (ret) + SSL_RET(failed2, "x509_load\n"); + + return x; + +failed2: + if (m) + X509_free(x); +failed1: + return NULL; +} + +/** + * @brief set SSL context client CA certification + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(x); + + if (ctx->client_CA == x) + return 1; + + X509_free(ctx->client_CA); + + ctx->client_CA = x; + + return 1; +} + +/** + * @brief add CA client certification into the SSL + */ +int SSL_add_client_CA(SSL *ssl, X509 *x) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(x); + + if (ssl->client_CA == x) + return 1; + + X509_free(ssl->client_CA); + + ssl->client_CA = x; + + return 1; +} + +/** + * @brief set the SSL context certification + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(x); + + if (ctx->cert->x509 == x) + return 1; + + X509_free(ctx->cert->x509); + + ctx->cert->x509 = x; + + return 1; +} + +/** + * @brief set the SSL certification + */ +int SSL_use_certificate(SSL *ssl, X509 *x) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(x); + + if (ssl->cert->x509 == x) + return 1; + + X509_free(ssl->cert->x509); + + ssl->cert->x509 = x; + + return 1; +} + +/** + * @brief get the SSL certification point + */ +X509 *SSL_get_certificate(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->cert->x509; +} + +/** + * @brief load certification into the SSL context + */ +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d) +{ + int ret; + X509 *x; + + x = d2i_X509(NULL, d, len); + if (!x) + SSL_RET(failed1, "d2i_X509\n"); + + ret = SSL_CTX_use_certificate(ctx, x); + if (!ret) + SSL_RET(failed2, "SSL_CTX_use_certificate\n"); + + return 1; + +failed2: + X509_free(x); +failed1: + return 0; +} + +/** + * @brief load certification into the SSL + */ +int SSL_use_certificate_ASN1(SSL *ssl, int len, + const unsigned char *d) +{ + int ret; + X509 *x; + + x = d2i_X509(NULL, d, len); + if (!x) + SSL_RET(failed1, "d2i_X509\n"); + + ret = SSL_use_certificate(ssl, x); + if (!ret) + SSL_RET(failed2, "SSL_use_certificate\n"); + + return 1; + +failed2: + X509_free(x); +failed1: + return 0; +} + +/** + * @brief load the certification file into SSL context + */ +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} + +/** + * @brief load the certification file into SSL + */ +int SSL_use_certificate_file(SSL *ssl, const char *file, int type) +{ + return 0; +} + +/** + * @brief get peer certification + */ +X509 *SSL_get_peer_certificate(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->session->peer; +} + diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c new file mode 100644 index 0000000000..92e72bfdb8 --- /dev/null +++ b/components/openssl/platform/ssl_pm.c @@ -0,0 +1,597 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "ssl_pm.h" +#include "ssl_port.h" +#include "ssl_dbg.h" + +/* mbedtls include */ +#include "mbedtls/platform.h" +#include "mbedtls/net.h" +#include "mbedtls/debug.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/error.h" +#include "mbedtls/certs.h" + +#if 0 + #define DEBUG_LOAD_BUF_STRING(str) SSL_DEBUG(1, "%s\n", str) +#else + #define DEBUG_LOAD_BUF_STRING(str) +#endif + +#define X509_INFO_STRING_LENGTH 1024 + +struct ssl_pm +{ + /* local socket file description */ + mbedtls_net_context fd; + /* remote client socket file description */ + mbedtls_net_context cl_fd; + + mbedtls_ssl_config conf; + + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_ssl_context ssl; + + mbedtls_entropy_context entropy; +}; + +struct x509_pm +{ + mbedtls_x509_crt *x509_crt; + + mbedtls_x509_crt *ex_crt; +}; + +struct pkey_pm +{ + mbedtls_pk_context *pkey; + + mbedtls_pk_context *ex_pkey; +}; + + +unsigned int max_content_len; + + +/*********************************************************************************************/ +/************************************ SSL arch interface *************************************/ + +/** + * @brief create SSL low-level object + */ +int ssl_pm_new(SSL *ssl) +{ + struct ssl_pm *ssl_pm; + int ret; + + const unsigned char pers[] = "OpenSSL PM"; + size_t pers_len = sizeof(pers); + + int endpoint; + int version; + + const SSL_METHOD *method = ssl->method; + + ssl_pm = ssl_mem_zalloc(sizeof(struct ssl_pm)); + if (!ssl_pm) + SSL_ERR(ret, failed1, "ssl_mem_zalloc\n"); + + if (ssl->ctx->read_buffer_len < 2048 || + ssl->ctx->read_buffer_len > 8192) + return -1; + + max_content_len = ssl->ctx->read_buffer_len; + + mbedtls_net_init(&ssl_pm->fd); + mbedtls_net_init(&ssl_pm->cl_fd); + + mbedtls_ssl_config_init(&ssl_pm->conf); + mbedtls_ctr_drbg_init(&ssl_pm->ctr_drbg); + mbedtls_entropy_init(&ssl_pm->entropy); + mbedtls_ssl_init(&ssl_pm->ssl); + + ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len); + if (ret) + SSL_ERR(ret, failed2, "mbedtls_ctr_drbg_seed:[-0x%x]\n", -ret); + + if (method->endpoint) { + endpoint = MBEDTLS_SSL_IS_SERVER; + } else { + endpoint = MBEDTLS_SSL_IS_CLIENT; + } + ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + if (ret) + SSL_ERR(ret, failed2, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); + + if (TLS_ANY_VERSION != ssl->version) { + if (TLS1_2_VERSION == ssl->version) + version = MBEDTLS_SSL_MINOR_VERSION_3; + else if (TLS1_1_VERSION == ssl->version) + version = MBEDTLS_SSL_MINOR_VERSION_2; + else if (TLS1_VERSION == ssl->version) + version = MBEDTLS_SSL_MINOR_VERSION_1; + else + version = MBEDTLS_SSL_MINOR_VERSION_0; + + mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version); + mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version); + } + + mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg); + + mbedtls_ssl_conf_dbg(&ssl_pm->conf, NULL, NULL); + + ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); + if (ret) + SSL_ERR(ret, failed3, "mbedtls_ssl_setup:[-0x%x]\n", -ret); + + mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL); + + ssl->ssl_pm = ssl_pm; + + return 0; + +failed3: + mbedtls_ssl_config_free(&ssl_pm->conf); + mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); +failed2: + mbedtls_entropy_free(&ssl_pm->entropy); + ssl_mem_free(ssl_pm); +failed1: + return -1; +} + +/** + * @brief free SSL low-level object + */ +void ssl_pm_free(SSL *ssl) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); + mbedtls_entropy_free(&ssl_pm->entropy); + mbedtls_ssl_config_free(&ssl_pm->conf); + mbedtls_ssl_free(&ssl_pm->ssl); + + ssl_mem_free(ssl_pm); + ssl->ssl_pm = NULL; +} + +/** + * @brief reload SSL low-level certification object + */ +static int ssl_pm_reload_crt(SSL *ssl) +{ + int ret; + int mode; + struct ssl_pm *ssl_pm = ssl->ssl_pm; + struct x509_pm *ca_pm = (struct x509_pm *)ssl->client_CA->x509_pm; + + struct pkey_pm *pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; + struct x509_pm *crt_pm = (struct x509_pm *)ssl->cert->x509->x509_pm; + + if (ssl->verify_mode == SSL_VERIFY_PEER) + mode = MBEDTLS_SSL_VERIFY_REQUIRED; + else if (ssl->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + mode = MBEDTLS_SSL_VERIFY_OPTIONAL; + else if (ssl->verify_mode == SSL_VERIFY_CLIENT_ONCE) + mode = MBEDTLS_SSL_VERIFY_UNSET; + else + mode = MBEDTLS_SSL_VERIFY_NONE; + + mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); + + if (ca_pm->x509_crt) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL); + } else if (ca_pm->ex_crt) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->ex_crt, NULL); + } + + if (crt_pm->x509_crt && pkey_pm->pkey) { + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->x509_crt, pkey_pm->pkey); + } else if (crt_pm->ex_crt && pkey_pm->ex_pkey) { + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->ex_crt, pkey_pm->ex_pkey); + } else { + ret = 0; + } + + if (ret) + return -1; + + return 0; +} + +int ssl_pm_handshake(SSL *ssl) +{ + int ret, mbed_ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbed_ret = ssl_pm_reload_crt(ssl); + if (mbed_ret) + return 0; + + ssl_speed_up_enter(); + while((mbed_ret = mbedtls_ssl_handshake(&ssl_pm->ssl)) != 0) { + if (mbed_ret != MBEDTLS_ERR_SSL_WANT_READ && mbed_ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + break; + } + } + ssl_speed_up_exit(); + + if (!mbed_ret) { + struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; + + ret = 1; + + x509_pm->ex_crt = (mbedtls_x509_crt *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl); + } else { + ret = 0; + SSL_DEBUG(1, "mbedtls_ssl_handshake [-0x%x]\n", -mbed_ret); + } + + return ret; +} + +int ssl_pm_shutdown(SSL *ssl) +{ + int ret, mbed_ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbed_ret = mbedtls_ssl_close_notify(&ssl_pm->ssl); + if (!mbed_ret) { + struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; + + ret = 0; + + x509_pm->ex_crt = NULL; + } + else + ret = -1; + + return ret; +} + +int ssl_pm_clear(SSL *ssl) +{ + return ssl_pm_shutdown(ssl); +} + + +int ssl_pm_read(SSL *ssl, void *buffer, int len) +{ + int ret, mbed_ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbed_ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len); + if (mbed_ret < 0) + ret = -1; + else if (mbed_ret == 0) + ret = 0; + else + ret = mbed_ret; + + return ret; +} + +int ssl_pm_send(SSL *ssl, const void *buffer, int len) +{ + int ret, mbed_ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbed_ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len); + if (mbed_ret < 0) + ret = -1; + else if (mbed_ret == 0) + ret = 0; + else + ret = mbed_ret; + + return ret; +} + +int ssl_pm_pending(const SSL *ssl) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + return mbedtls_ssl_get_bytes_avail(&ssl_pm->ssl); +} + +void ssl_pm_set_fd(SSL *ssl, int fd, int mode) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ssl_pm->fd.fd = fd; +} + +int ssl_pm_get_fd(const SSL *ssl, int mode) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + return ssl_pm->fd.fd; +} + +OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl) +{ + OSSL_HANDSHAKE_STATE state; + + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + switch (ssl_pm->ssl.state) + { + case MBEDTLS_SSL_CLIENT_HELLO: + state = TLS_ST_CW_CLNT_HELLO; + break; + case MBEDTLS_SSL_SERVER_HELLO: + state = TLS_ST_SW_SRVR_HELLO; + break; + case MBEDTLS_SSL_SERVER_CERTIFICATE: + state = TLS_ST_SW_CERT; + break; + case MBEDTLS_SSL_SERVER_HELLO_DONE: + state = TLS_ST_SW_SRVR_DONE; + break; + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + state = TLS_ST_CW_KEY_EXCH; + break; + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + state = TLS_ST_CW_CHANGE; + break; + case MBEDTLS_SSL_CLIENT_FINISHED: + state = TLS_ST_CW_FINISHED; + break; + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: + state = TLS_ST_SW_CHANGE; + break; + case MBEDTLS_SSL_SERVER_FINISHED: + state = TLS_ST_SW_FINISHED; + break; + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + state = TLS_ST_CW_CERT; + break; + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + state = TLS_ST_SR_KEY_EXCH; + break; + case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: + state = TLS_ST_SW_SESSION_TICKET; + break; + case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT: + state = TLS_ST_SW_CERT_REQ; + break; + case MBEDTLS_SSL_HANDSHAKE_OVER: + state = TLS_ST_OK; + break; + default : + state = TLS_ST_BEFORE; + break; + } + + return state; +} + +int x509_pm_show_info(X509 *x) +{ + int ret; + char *buf; + mbedtls_x509_crt *x509_crt; + struct x509_pm *x509_pm = x->x509_pm; + + if (x509_pm->x509_crt) + x509_crt = x509_pm->x509_crt; + else if (x509_pm->ex_crt) + x509_crt = x509_pm->ex_crt; + else + x509_crt = NULL; + + if (!x509_crt) + return -1; + + buf = ssl_mem_malloc(X509_INFO_STRING_LENGTH); + if (!buf) + SSL_RET(failed1, ""); + + ret = mbedtls_x509_crt_info(buf, X509_INFO_STRING_LENGTH - 1, "", x509_crt); + if (ret <= 0) + SSL_RET(failed2, ""); + buf[ret] = 0; + + ssl_mem_free(buf); + + SSL_DEBUG(1, "%s", buf); + + return 0; + +failed2: + ssl_mem_free(buf); +failed1: + return -1; +} + +int x509_pm_new(X509 *x, X509 *m_x) +{ + struct x509_pm *x509_pm; + + x509_pm = ssl_mem_zalloc(sizeof(struct x509_pm)); + if (!x509_pm) + SSL_RET(failed1, "ssl_mem_zalloc\n"); + + x->x509_pm = x509_pm; + + if (m_x) { + struct x509_pm *m_x509_pm = (struct x509_pm *)m_x->x509_pm; + + x509_pm->ex_crt = m_x509_pm->x509_crt; + } + + return 0; + +failed1: + return -1; +} + +void x509_pm_free(X509 *x) +{ + struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; + + if (x509_pm->x509_crt) { + mbedtls_x509_crt_free(x509_pm->x509_crt); + + ssl_mem_free(x509_pm->x509_crt); + x509_pm->x509_crt = NULL; + } + + ssl_mem_free(x->x509_pm); + x->x509_pm = NULL; +} + +int x509_pm_load(X509 *x, const unsigned char *buffer, int len) +{ + int ret; + unsigned char *load_buf; + struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; + + if (x509_pm->x509_crt) + mbedtls_x509_crt_free(x509_pm->x509_crt); + + if (!x509_pm->x509_crt) { + x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt)); + if (!x509_pm->x509_crt) + SSL_RET(failed1, "ssl_mem_malloc\n"); + } + + load_buf = ssl_mem_malloc(len + 1); + if (!load_buf) + SSL_RET(failed2, "ssl_mem_malloc\n"); + + ssl_memcpy(load_buf, buffer, len); + load_buf[len] = '\0'; + + DEBUG_LOAD_BUF_STRING(load_buf); + + mbedtls_x509_crt_init(x509_pm->x509_crt); + + ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len + 1); + ssl_mem_free(load_buf); + + if (ret) + SSL_RET(failed2, "mbedtls_x509_crt_parse, return [-0x%x]\n", -ret); + + return 0; + +failed2: + ssl_mem_free(x509_pm->x509_crt); + x509_pm->x509_crt = NULL; +failed1: + return -1; +} + +int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pkey) +{ + struct pkey_pm *pkey_pm; + + pkey_pm = ssl_mem_zalloc(sizeof(struct pkey_pm)); + if (!pkey_pm) + return -1; + + pk->pkey_pm = pkey_pm; + + if (m_pkey) { + struct pkey_pm *m_pkey_pm = (struct pkey_pm *)m_pkey->pkey_pm; + + pkey_pm->ex_pkey = m_pkey_pm->pkey; + } + + return 0; +} + +void pkey_pm_free(EVP_PKEY *pk) +{ + struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm; + + if (pkey_pm->pkey) { + mbedtls_pk_free(pkey_pm->pkey); + + ssl_mem_free(pkey_pm->pkey); + pkey_pm->pkey = NULL; + } + + ssl_mem_free(pk->pkey_pm); + pk->pkey_pm = NULL; +} + +int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) +{ + int ret; + unsigned char *load_buf; + struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm; + + if (pkey_pm->pkey) + mbedtls_pk_free(pkey_pm->pkey); + + if (!pkey_pm->pkey) { + pkey_pm->pkey = ssl_mem_malloc(sizeof(mbedtls_pk_context)); + if (!pkey_pm->pkey) + SSL_RET(failed1, "ssl_mem_malloc\n"); + } + + load_buf = ssl_mem_malloc(len + 1); + if (!load_buf) + SSL_RET(failed2, "ssl_mem_malloc\n"); + + ssl_memcpy(load_buf, buffer, len); + load_buf[len] = '\0'; + + DEBUG_LOAD_BUF_STRING(load_buf); + + mbedtls_pk_init(pkey_pm->pkey); + + ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len + 1, NULL, 0); + ssl_mem_free(load_buf); + + if (ret) + SSL_RET(failed2, "mbedtls_pk_parse_key, return [-0x%x]\n", -ret); + + return 0; + +failed2: + ssl_mem_free(pkey_pm->pkey); + pkey_pm->pkey = NULL; +failed1: + return -1; +} + + + +void ssl_pm_set_bufflen(SSL *ssl, int len) +{ + max_content_len = len; +} + +long ssl_pm_get_verify_result(const SSL *ssl) +{ + long ret; + long verify_result; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ret = mbedtls_ssl_get_verify_result(&ssl_pm->ssl); + + if (!ret) + verify_result = X509_V_OK; + else + verify_result = X509_V_ERR_UNSPECIFIED; + + return verify_result; +} diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c new file mode 100644 index 0000000000..ae3b849ca3 --- /dev/null +++ b/components/openssl/platform/ssl_port.c @@ -0,0 +1,66 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "ssl_port.h" + +#ifdef ESP32_IDF_PLATFORM + +#include "string.h" +#include "malloc.h" + +/*********************************************************************************************/ +/********************************* SSL general interface *************************************/ + +void* ssl_mem_zalloc(size_t size) +{ + void *p = malloc(size); + + if (p) + memset(p, 0, size); + + return p; +} + +void *ssl_mem_malloc(size_t size) +{ + return malloc(size); +} + +void ssl_mem_free(void *p) +{ + free(p); +} + +void* ssl_memcpy(void *to, const void *from, size_t size) +{ + return memcpy(to, from, size); +} + +size_t ssl_strlen(const char *src) +{ + return strlen(src); +} + +void ssl_speed_up_enter(void) +{ + +} + +void ssl_speed_up_exit(void) +{ + +} + +#endif + diff --git a/components/partition_table/Makefile.projbuild b/components/partition_table/Makefile.projbuild index 98631cc854..5bd13f766d 100644 --- a/components/partition_table/Makefile.projbuild +++ b/components/partition_table/Makefile.projbuild @@ -11,6 +11,8 @@ # NB: gen_esp32part.py lives in the sdk/bin/ dir not component dir GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q +PARTITION_TABLE_OFFSET := 0x8000 + # Path to partition CSV file is relative to project path for custom # partition CSV files, but relative to component dir otherwise.$ PARTITION_TABLE_ROOT := $(call dequote,$(if $(CONFIG_PARTITION_TABLE_CUSTOM),$(PROJECT_PATH),$(COMPONENT_PATH))) @@ -18,28 +20,38 @@ PARTITION_TABLE_CSV_PATH := $(call dequote,$(abspath $(PARTITION_TABLE_ROOT)/$(s PARTITION_TABLE_BIN := $(BUILD_DIR_BASE)/$(notdir $(PARTITION_TABLE_CSV_PATH:.csv=.bin)) -$(PARTITION_TABLE_BIN): $(PARTITION_TABLE_CSV_PATH) +ifdef CONFIG_SECURE_BOOTLOADER_ENABLED +PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN:.bin=-unsigned.bin) +# add an extra signing step for secure partition table +$(PARTITION_TABLE_BIN): $(PARTITION_TABLE_BIN_UNSIGNED) + $(Q) $(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $< +else +# secure bootloader disabled, both files are the same +PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN) +endif + +$(PARTITION_TABLE_BIN_UNSIGNED): $(PARTITION_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFILE) @echo "Building partitions from $(PARTITION_TABLE_CSV_PATH)..." - $(Q) $(GEN_ESP32PART) $< $@ + $(GEN_ESP32PART) $< $@ all_binaries: $(PARTITION_TABLE_BIN) -PARTITION_TABLE_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash 0x4000 $(PARTITION_TABLE_BIN) -ESPTOOL_ALL_FLASH_ARGS += 0x4000 $(PARTITION_TABLE_BIN) +PARTITION_TABLE_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN) +ESPTOOL_ALL_FLASH_ARGS += $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN) partition_table: $(PARTITION_TABLE_BIN) @echo "Partition table binary generated. Contents:" @echo $(SEPARATOR) - $(Q) $(GEN_ESP32PART) $< + $(GEN_ESP32PART) $< @echo $(SEPARATOR) @echo "Partition flashing command:" @echo "$(PARTITION_TABLE_FLASH_CMD)" partition_table-flash: $(PARTITION_TABLE_BIN) @echo "Flashing partition table..." - $(Q) $(PARTITION_TABLE_FLASH_CMD) + $(PARTITION_TABLE_FLASH_CMD) partition_table-clean: - $(Q) rm -f $(PARTITION_TABLE_BIN) + rm -f $(PARTITION_TABLE_BIN) clean: partition_table-clean diff --git a/components/partition_table/gen_esp32part.py b/components/partition_table/gen_esp32part.py index 8b5df2b3b5..cb6a5f24a1 100755 --- a/components/partition_table/gen_esp32part.py +++ b/components/partition_table/gen_esp32part.py @@ -9,6 +9,8 @@ import struct import argparse import sys +MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature + __version__ = '1.0' quiet = False @@ -84,15 +86,22 @@ class PartitionTable(list): @classmethod def from_binary(cls, b): - if len(b) % 32 != 0: - raise InputError("Partition table length must be a multiple of 32 bytes. Got %d bytes." % len(b)) result = cls() for o in range(0,len(b),32): - result.append(PartitionDefinition.from_binary(b[o:o+32])) + data = b[o:o+32] + if len(data) != 32: + raise InputError("Ran out of partition table data before reaching end marker") + if data == '\xFF'*32: + break # end of partition table + result.append(PartitionDefinition.from_binary(data)) return result def to_binary(self): - return "".join(e.to_binary() for e in self) + result = "".join(e.to_binary() for e in self) + if len(result )>= MAX_PARTITION_LENGTH: + raise InputError("Binary partition table length (%d) longer than max" % len(result)) + result += "\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing + return result def to_csv(self, simple_formatting=False): rows = [ "# Espressif ESP32 Partition Table", diff --git a/components/partition_table/tests/gen_esp32part_tests.py b/components/partition_table/tests/gen_esp32part_tests.py index 413f1aac91..d12539ea87 100755 --- a/components/partition_table/tests/gen_esp32part_tests.py +++ b/components/partition_table/tests/gen_esp32part_tests.py @@ -37,6 +37,10 @@ LONGER_BINARY_TABLE += "\xAA\x50\x10\x00" + \ "second" + ("\0"*10) + \ "\x00\x00\x00\x00" +def _strip_trailing_ffs(binary_table): + while binary_table.endswith("\xFF"): + binary_table = binary_table[0:len(binary_table)-1] + return binary_table class CSVParserTests(unittest.TestCase): @@ -156,7 +160,7 @@ class BinaryOutputTests(unittest.TestCase): first, 0x30, 0xEE, 0x100400, 0x300000 """ t = PartitionTable.from_csv(csv) - tb = t.to_binary() + tb = _strip_trailing_ffs(t.to_binary()) self.assertEqual(len(tb), 32) self.assertEqual('\xAA\x50', tb[0:2]) # magic self.assertEqual('\x30\xee', tb[2:4]) # type, subtype @@ -170,7 +174,7 @@ first, 0x30, 0xEE, 0x100400, 0x300000 second,0x31, 0xEF, , 0x100000 """ t = PartitionTable.from_csv(csv) - tb = t.to_binary() + tb = _strip_trailing_ffs(t.to_binary()) self.assertEqual(len(tb), 64) self.assertEqual('\xAA\x50', tb[0:2]) self.assertEqual('\xAA\x50', tb[32:34]) @@ -215,7 +219,7 @@ class BinaryParserTests(unittest.TestCase): self.assertEqual(t[2].type, 0x10) self.assertEqual(t[2].name, "second") - round_trip = t.to_binary() + round_trip = _strip_trailing_ffs(t.to_binary()) self.assertEqual(round_trip, LONGER_BINARY_TABLE) def test_bad_magic(self): @@ -267,7 +271,7 @@ class CSVOutputTests(unittest.TestCase): self.assertEqual(row[0], "factory") self.assertEqual(row[1], "app") self.assertEqual(row[2], "2") - self.assertEqual(row[3], "64K") + self.assertEqual(row[3], "0x10000") self.assertEqual(row[4], "1M") # round trip back to a PartitionTable and check is identical @@ -291,7 +295,7 @@ class CommandLineTests(unittest.TestCase): # reopen the CSV and check the generated binary is identical with open(csvpath, 'r') as f: from_csv = PartitionTable.from_csv(f.read()) - self.assertEqual(from_csv.to_binary(), LONGER_BINARY_TABLE) + self.assertEqual(_strip_trailing_ffs(from_csv.to_binary()), LONGER_BINARY_TABLE) # run gen_esp32part.py to conver the CSV to binary again subprocess.check_call([sys.executable, "../gen_esp32part.py", @@ -299,6 +303,7 @@ class CommandLineTests(unittest.TestCase): # assert that file reads back as identical with open(binpath, 'rb') as f: binary_readback = f.read() + binary_readback = _strip_trailing_ffs(binary_readback) self.assertEqual(binary_readback, LONGER_BINARY_TABLE) finally: diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst new file mode 100644 index 0000000000..b479c3b0e9 --- /dev/null +++ b/components/spi_flash/README.rst @@ -0,0 +1,158 @@ +SPI flash related APIs +====================== + +Overview +-------- +Spi_flash component contains APIs related to reading, writing, erasing, +memory mapping data in the external SPI flash. It also has higher-level +APIs which work with partition table and partitions. + +Note that all the functionality is limited to the "main" flash chip, +i.e. the flash chip from which program runs. For ``spi_flash_*`` functions, +this is software limitation. Underlying ROM functions which work with SPI flash +do not have provisions for working with flash chips attached to SPI peripherals +other than SPI0. + +SPI flash access APIs +--------------------- + +This is the set of APIs for working with data in flash: + +- ``spi_flash_read`` used to read data from flash to RAM +- ``spi_flash_write`` used to write data from RAM to flash +- ``spi_flash_erase_sector`` used to erase individual sectors of flash +- ``spi_flash_erase_range`` used to erase range of addresses in flash +- ``spi_flash_get_chip_size`` returns flash chip size, in bytes, as configured in menuconfig + +There are some data alignment limitations which need to be considered when using +spi_flash_read/spi_flash_write functions: + +- buffer in RAM must be 4-byte aligned +- size must be 4-byte aligned +- address in flash must be 4-byte aligned + +These alignment limitations are purely software, and should be removed in future +versions. + +It is assumed that correct SPI flash chip size is set at compile time using +menuconfig. While run-time detection of SPI flash chip size is possible, it is +not implemented yet. Applications which need this (e.g. to provide one firmware +binary for different flash sizes) can do flash chip size detection and set +the correct flash chip size in ``chip_size`` member of ``g_rom_flashchip`` +structure. This size is used by ``spi_flash_*`` functions for bounds checking. + +SPI flash APIs disable instruction and data caches while reading/writing/erasing. +See implementation notes below on details how this happens. For application +this means that at some periods of time, code can not be run from flash, +and constant data can not be fetched from flash by the CPU. This is not an +issue for normal code which runs in a task, because SPI flash APIs prevent +other tasks from running while caches are disabled. This is an issue for +interrupt handlers, which can still be called while flash operation is in +progress. If the interrupt handler is not placed into IRAM, there is a +possibility that interrupt will happen at the time when caches are disabled, +which will cause an illegal instruction exception. + +To prevent this, make sure that all ISR code, and all functions called from ISR +code are placed into IRAM, or are located in ROM. Most useful C library +functions are located in ROM, so they can be called from ISR. + +To place a function into IRAM, use ``IRAM_ATTR`` attribute, e.g.:: + + #include "esp_attr.h" + + void IRAM_ATTR gpio_isr_handler(void* arg) + { + // ... + } + +When flash encryption is enabled, ``spi_flash_read`` will read data as it is +stored in flash (without decryption), and ``spi_flash_write`` will write data +in plain text. In other words, ``spi_flash_read/write`` APIs don't have +provisions to deal with encrypted data. + + +Partition table APIs +-------------------- + +ESP-IDF uses partition table to maintain information about various regions of +SPI flash memory (bootloader, various application binaries, data, filesystems). +More information about partition tables can be found in docs/partition_tables.rst. + +This component provides APIs to enumerate partitions found in the partition table +and perform operations on them. These functions are declared in ``esp_partition.h``: + +- ``esp_partition_find`` used to search partition table for entries with specific type, returns an opaque iterator +- ``esp_partition_get`` returns a structure describing the partition, for the given iterator +- ``esp_partition_next`` advances iterator to the next partition found +- ``esp_partition_iterator_release`` releases iterator returned by ``esp_partition_find`` +- ``esp_partition_find_first`` is a convenience function which returns structure describing the first partition found by esp_partition_find +- ``esp_partition_read``, ``esp_partition_write``, ``esp_partition_erase_range`` are equivalent to ``spi_flash_read``, ``spi_flash_write``, ``spi_flash_erase_range``, but operate within partition boundaries + +Most application code should use ``esp_partition_*`` APIs instead of lower level +``spi_flash_*`` APIs. Partition APIs do bounds checking and calculate correct +offsets in flash based on data stored in partition table. + +Memory mapping APIs +------------------- + +ESP32 features memory hardware which allows regions of flash memory to be mapped +into instruction and data address spaces. This mapping works only for read operations, +it is not possible to modify contents of flash memory by writing to mapped memory +region. Mapping happens in 64KB pages. Memory mapping hardware can map up to +4 megabytes of flash into data address space, and up to 16 megabytes of flash into +instruction address space. See the technical reference manual for more details +about memory mapping hardware. + +Note that some number of 64KB pages is used to map the application +itself into memory, so the actual number of available 64KB pages may be less. + +Reading data from flash using a memory mapped region is the only way to decrypt +contents of flash when flash encryption is enabled. Decryption is performed at +hardware level. + +Memory mapping APIs are declared in ``esp_spi_flash.h`` and ``esp_partition.h``: + +- ``spi_flash_mmap`` maps a region of physical flash addresses into instruction space or data space of the CPU +- ``spi_flash_munmap`` unmaps previously mapped region +- ``esp_partition_mmap`` maps part of a partition into the instruction space or data space of the CPU + +Differences between ``spi_flash_mmap`` and ``esp_partition_mmap`` are as follows: + +- ``spi_flash_mmap`` must be given a 64KB aligned physical address +- ``esp_partition_mmap`` may be given an arbitrary offset within the partition, it will adjust returned pointer to mapped memory as necessary + +Note that because memory mapping happens in 64KB blocks, it may be possible to +read data outside of the partition provided to ``esp_partition_mmap``. + +Implementation notes +-------------------- + +In order to perform some flash operations, we need to make sure both CPUs +are not running any code from flash for the duration of the flash operation. +In a single-core setup this is easy: we disable interrupts/scheduler and do +the flash operation. In the dual-core setup this is slightly more complicated. +We need to make sure that the other CPU doesn't run any code from flash. + + +When SPI flash API is called on CPU A (can be PRO or APP), we start +spi_flash_op_block_func function on CPU B using esp_ipc_call API. This API +wakes up high priority task on CPU B and tells it to execute given function, +in this case spi_flash_op_block_func. This function disables cache on CPU B and +signals that cache is disabled by setting s_flash_op_can_start flag. +Then the task on CPU A disables cache as well, and proceeds to execute flash +operation. + +While flash operation is running, interrupts can still run on CPUs A and B. +We assume that all interrupt code is placed into RAM. Once interrupt allocation +API is added, we should add a flag to request interrupt to be disabled for +the duration of flash operations. + +Once flash operation is complete, function on CPU A sets another flag, +s_flash_op_complete, to let the task on CPU B know that it can re-enable +cache and release the CPU. Then the function on CPU A re-enables the cache on +CPU A as well and returns control to the calling code. + +Additionally, all API functions are protected with a mutex (s_flash_op_mutex). + +In a single core environment (CONFIG_FREERTOS_UNICORE enabled), we simply +disable both caches, no inter-CPU communication takes place. diff --git a/components/spi_flash/esp_spi_flash.c b/components/spi_flash/cache_utils.c similarity index 52% rename from components/spi_flash/esp_spi_flash.c rename to components/spi_flash/cache_utils.c index d702f3b815..904007b316 100644 --- a/components/spi_flash/esp_spi_flash.c +++ b/components/spi_flash/cache_utils.c @@ -3,7 +3,7 @@ // 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 @@ -30,39 +30,7 @@ #include "esp_spi_flash.h" #include "esp_log.h" -/* - Driver for SPI flash read/write/erase operations - In order to perform some flash operations, we need to make sure both CPUs - are not running any code from flash for the duration of the flash operation. - In a single-core setup this is easy: we disable interrupts/scheduler and do - the flash operation. In the dual-core setup this is slightly more complicated. - We need to make sure that the other CPU doesn't run any code from flash. - - - When SPI flash API is called on CPU A (can be PRO or APP), we start - spi_flash_op_block_func function on CPU B using esp_ipc_call API. This API - wakes up high priority task on CPU B and tells it to execute given function, - in this case spi_flash_op_block_func. This function disables cache on CPU B and - signals that cache is disabled by setting s_flash_op_can_start flag. - Then the task on CPU A disables cache as well, and proceeds to execute flash - operation. - - While flash operation is running, interrupts can still run on CPU B. - We assume that all interrupt code is placed into RAM. - - Once flash operation is complete, function on CPU A sets another flag, - s_flash_op_complete, to let the task on CPU B know that it can re-enable - cache and release the CPU. Then the function on CPU A re-enables the cache on - CPU A as well and returns control to the calling code. - - Additionally, all API functions are protected with a mutex (s_flash_op_mutex). - - In a single core environment (CONFIG_FREERTOS_UNICORE enabled), we simply - disable both caches, no inter-CPU communication takes place. -*/ - -static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc); static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state); static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state); @@ -70,27 +38,25 @@ static uint32_t s_flash_op_cache_state[2]; #ifndef CONFIG_FREERTOS_UNICORE static SemaphoreHandle_t s_flash_op_mutex; -static bool s_flash_op_can_start = false; -static bool s_flash_op_complete = false; -#endif //CONFIG_FREERTOS_UNICORE +static volatile bool s_flash_op_can_start = false; +static volatile bool s_flash_op_complete = false; -#if CONFIG_SPI_FLASH_ENABLE_COUNTERS -static const char* TAG = "spi_flash"; -static spi_flash_counters_t s_flash_stats; +void spi_flash_init_lock() +{ + s_flash_op_mutex = xSemaphoreCreateMutex(); +} -#define COUNTER_START() uint32_t ts_begin = xthal_get_ccount() -#define COUNTER_STOP(counter) do{ s_flash_stats.counter.count++; s_flash_stats.counter.time += (xthal_get_ccount() - ts_begin) / (XT_CLOCK_FREQ / 1000000); } while(0) -#define COUNTER_ADD_BYTES(counter, size) do { s_flash_stats.counter.bytes += size; } while (0) -#else -#define COUNTER_START() -#define COUNTER_STOP(counter) -#define COUNTER_ADD_BYTES(counter, size) +void spi_flash_op_lock() +{ + xSemaphoreTake(s_flash_op_mutex, portMAX_DELAY); +} -#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS +void spi_flash_op_unlock() +{ + xSemaphoreGive(s_flash_op_mutex); +} -#ifndef CONFIG_FREERTOS_UNICORE - -static void IRAM_ATTR spi_flash_op_block_func(void* arg) +void IRAM_ATTR spi_flash_op_block_func(void* arg) { // Disable scheduler on this CPU vTaskSuspendAll(); @@ -108,19 +74,9 @@ static void IRAM_ATTR spi_flash_op_block_func(void* arg) xTaskResumeAll(); } -void spi_flash_init() +void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() { - s_flash_op_mutex = xSemaphoreCreateMutex(); - -#if CONFIG_SPI_FLASH_ENABLE_COUNTERS - spi_flash_reset_counters(); -#endif -} - -static void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() -{ - // Take the API lock - xSemaphoreTake(s_flash_op_mutex, portMAX_DELAY); + spi_flash_op_lock(); const uint32_t cpuid = xPortGetCoreID(); const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; @@ -152,7 +108,7 @@ static void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]); } -static void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() +void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() { const uint32_t cpuid = xPortGetCoreID(); const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; @@ -173,98 +129,45 @@ static void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() xTaskResumeAll(); } // Release API lock - xSemaphoreGive(s_flash_op_mutex); + spi_flash_op_unlock(); } -#else // CONFIG_FREERTOS_UNICORE +#else // CONFIG_FREERTOS_UNICORE -void spi_flash_init() +void spi_flash_init_lock() { -#if CONFIG_SPI_FLASH_ENABLE_COUNTERS - spi_flash_reset_counters(); -#endif } -static void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() +void spi_flash_op_lock() { vTaskSuspendAll(); +} + +void spi_flash_op_unlock() +{ + xTaskResumeAll(); +} + + +void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() +{ + spi_flash_op_lock(); spi_flash_disable_cache(0, &s_flash_op_cache_state[0]); } -static void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() +void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() { spi_flash_restore_cache(0, s_flash_op_cache_state[0]); - xTaskResumeAll(); + spi_flash_op_unlock(); } #endif // CONFIG_FREERTOS_UNICORE - -SpiFlashOpResult IRAM_ATTR spi_flash_unlock() -{ - static bool unlocked = false; - if (!unlocked) { - SpiFlashOpResult rc = SPIUnlock(); - if (rc != SPI_FLASH_RESULT_OK) { - return rc; - } - unlocked = true; - } - return SPI_FLASH_RESULT_OK; -} - -esp_err_t IRAM_ATTR spi_flash_erase_sector(uint16_t sec) -{ - COUNTER_START(); - spi_flash_disable_interrupts_caches_and_other_cpu(); - SpiFlashOpResult rc; - rc = spi_flash_unlock(); - if (rc == SPI_FLASH_RESULT_OK) { - rc = SPIEraseSector(sec); - } - spi_flash_enable_interrupts_caches_and_other_cpu(); - COUNTER_STOP(erase); - return spi_flash_translate_rc(rc); -} - -esp_err_t IRAM_ATTR spi_flash_write(uint32_t dest_addr, const uint32_t *src, uint32_t size) -{ - COUNTER_START(); - spi_flash_disable_interrupts_caches_and_other_cpu(); - SpiFlashOpResult rc; - rc = spi_flash_unlock(); - if (rc == SPI_FLASH_RESULT_OK) { - rc = SPIWrite(dest_addr, src, (int32_t) size); - COUNTER_ADD_BYTES(write, size); - } - spi_flash_enable_interrupts_caches_and_other_cpu(); - COUNTER_STOP(write); - return spi_flash_translate_rc(rc); -} - -esp_err_t IRAM_ATTR spi_flash_read(uint32_t src_addr, uint32_t *dest, uint32_t size) -{ - COUNTER_START(); - spi_flash_disable_interrupts_caches_and_other_cpu(); - SpiFlashOpResult rc = SPIRead(src_addr, dest, (int32_t) size); - COUNTER_ADD_BYTES(read, size); - spi_flash_enable_interrupts_caches_and_other_cpu(); - COUNTER_STOP(read); - return spi_flash_translate_rc(rc); -} - -static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc) -{ - switch (rc) { - case SPI_FLASH_RESULT_OK: - return ESP_OK; - case SPI_FLASH_RESULT_TIMEOUT: - return ESP_ERR_FLASH_OP_TIMEOUT; - case SPI_FLASH_RESULT_ERR: - default: - return ESP_ERR_FLASH_OP_FAIL; - } -} +/** + * The following two functions are replacements for Cache_Read_Disable and Cache_Read_Enable + * function in ROM. They are used to work around a bug where Cache_Read_Disable requires a call to + * Cache_Flush before Cache_Read_Enable, even if cached data was not modified. + */ static const uint32_t cache_mask = DPORT_APP_CACHE_MASK_OPSDRAM | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 | DPORT_APP_CACHE_MASK_IROM0 | @@ -300,29 +203,3 @@ static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_sta } } -#if CONFIG_SPI_FLASH_ENABLE_COUNTERS - -static inline void dump_counter(spi_flash_counter_t* counter, const char* name) -{ - ESP_LOGI(TAG, "%s count=%8d time=%8dms bytes=%8d\n", name, - counter->count, counter->time, counter->bytes); -} - -const spi_flash_counters_t* spi_flash_get_counters() -{ - return &s_flash_stats; -} - -void spi_flash_reset_counters() -{ - memset(&s_flash_stats, 0, sizeof(s_flash_stats)); -} - -void spi_flash_dump_counters() -{ - dump_counter(&s_flash_stats.read, "read "); - dump_counter(&s_flash_stats.write, "write"); - dump_counter(&s_flash_stats.erase, "erase"); -} - -#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS diff --git a/components/spi_flash/cache_utils.h b/components/spi_flash/cache_utils.h new file mode 100644 index 0000000000..899a31c651 --- /dev/null +++ b/components/spi_flash/cache_utils.h @@ -0,0 +1,44 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 ESP_SPI_FLASH_CACHE_UTILS_H +#define ESP_SPI_FLASH_CACHE_UTILS_H + +/** + * This header file contains declarations of cache manipulation functions + * used both in flash_ops.c and flash_mmap.c. + * + * These functions are considered internal and are not designed to be called from applications. + */ + +// Init mutex protecting access to spi_flash_* APIs +void spi_flash_init_lock(); + +// Take mutex protecting access to spi_flash_* APIs +void spi_flash_op_lock(); + +// Release said mutex +void spi_flash_op_unlock(); + +// Suspend the scheduler on both CPUs, disable cache. +// Contrary to its name this doesn't do anything with interrupts, yet. +// Interrupt disabling capability will be added once we implement +// interrupt allocation API. +void spi_flash_disable_interrupts_caches_and_other_cpu(); + +// Enable cache, enable interrupts (to be added in future), resume scheduler +void spi_flash_enable_interrupts_caches_and_other_cpu(); + + +#endif //ESP_SPI_FLASH_CACHE_UTILS_H diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk index ef497a7ecb..d511eedb8e 100755 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -1,3 +1,7 @@ COMPONENT_ADD_INCLUDEDIRS := include -include $(IDF_PATH)/make/component_common.mk +ifdef IS_BOOTLOADER_BUILD +# Bootloader needs updated SPIUnlock from this file +COMPONENT_OBJS := spi_flash_rom_patch.o +endif + diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c new file mode 100644 index 0000000000..2165a784d1 --- /dev/null +++ b/components/spi_flash/flash_mmap.c @@ -0,0 +1,214 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_ipc.h" +#include "esp_attr.h" +#include "esp_spi_flash.h" +#include "esp_log.h" +#include "cache_utils.h" + +#ifndef NDEBUG +// Enable built-in checks in queue.h in debug builds +#define INVARIANTS +#endif +#include "rom/queue.h" + +#define REGIONS_COUNT 4 +#define PAGES_PER_REGION 64 +#define FLASH_PAGE_SIZE 0x10000 +#define INVALID_ENTRY_VAL 0x100 +#define VADDR0_START_ADDR 0x3F400000 +#define VADDR1_START_ADDR 0x40000000 +#define VADDR1_FIRST_USABLE_ADDR 0x400D0000 +#define PRO_IRAM0_FIRST_USABLE_PAGE ((VADDR1_FIRST_USABLE_ADDR - VADDR1_START_ADDR) / FLASH_PAGE_SIZE + 64) + + +typedef struct mmap_entry_{ + uint32_t handle; + int page; + int count; + LIST_ENTRY(mmap_entry_) entries; +} mmap_entry_t; + + +static LIST_HEAD(mmap_entries_head, mmap_entry_) s_mmap_entries_head = + LIST_HEAD_INITIALIZER(s_mmap_entries_head); +static uint8_t s_mmap_page_refcnt[REGIONS_COUNT * PAGES_PER_REGION] = {0}; +static uint32_t s_mmap_last_handle = 0; + + +static void IRAM_ATTR spi_flash_mmap_init() +{ + for (int i = 0; i < REGIONS_COUNT * PAGES_PER_REGION; ++i) { + uint32_t entry_pro = DPORT_PRO_FLASH_MMU_TABLE[i]; + uint32_t entry_app = DPORT_APP_FLASH_MMU_TABLE[i]; + if (entry_pro != entry_app) { + // clean up entries used by boot loader + entry_pro = 0; + DPORT_PRO_FLASH_MMU_TABLE[i] = 0; + } + if ((entry_pro & 0x100) == 0 && (i == 0 || i == PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) { + s_mmap_page_refcnt[i] = 1; + } + } +} + +esp_err_t IRAM_ATTR spi_flash_mmap(uint32_t src_addr, size_t size, spi_flash_mmap_memory_t memory, + const void** out_ptr, spi_flash_mmap_handle_t* out_handle) +{ + esp_err_t ret; + mmap_entry_t* new_entry = (mmap_entry_t*) malloc(sizeof(mmap_entry_t)); + if (new_entry == 0) { + return ESP_ERR_NO_MEM; + } + if (src_addr & 0xffff) { + return ESP_ERR_INVALID_ARG; + } + if (src_addr + size > g_rom_flashchip.chip_size) { + return ESP_ERR_INVALID_ARG; + } + spi_flash_disable_interrupts_caches_and_other_cpu(); + if (s_mmap_page_refcnt[0] == 0) { + spi_flash_mmap_init(); + } + // figure out the memory region where we should look for pages + int region_begin; // first page to check + int region_size; // number of pages to check + uint32_t region_addr; // base address of memory region + if (memory == SPI_FLASH_MMAP_DATA) { + // Vaddr0 + region_begin = 0; + region_size = 64; + region_addr = VADDR0_START_ADDR; + } else { + // only part of VAddr1 is usable, so adjust for that + region_begin = VADDR1_FIRST_USABLE_ADDR; + region_size = 3 * 64 - region_begin; + region_addr = VADDR1_FIRST_USABLE_ADDR; + } + // region which should be mapped + int phys_page = src_addr / FLASH_PAGE_SIZE; + int page_count = (size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE; + // The following part searches for a range of MMU entries which can be used. + // Algorithm is essentially naïve strstr algorithm, except that unused MMU + // entries are treated as wildcards. + int start; + int end = region_begin + region_size - page_count; + for (start = region_begin; start < end; ++start) { + int page = phys_page; + int pos; + for (pos = start; pos < start + page_count; ++pos, ++page) { + int table_val = (int) DPORT_PRO_FLASH_MMU_TABLE[pos]; + uint8_t refcnt = s_mmap_page_refcnt[pos]; + if (refcnt != 0 && table_val != page) { + break; + } + } + // whole mapping range matched, bail out + if (pos - start == page_count) { + break; + } + } + // checked all the region(s) and haven't found anything? + if (start == end) { + *out_handle = 0; + *out_ptr = NULL; + ret = ESP_ERR_NO_MEM; + } else { + // set up mapping using pages [start, start + page_count) + uint32_t entry_val = (uint32_t) phys_page; + for (int i = start; i != start + page_count; ++i, ++entry_val) { + // sanity check: we won't reconfigure entries with non-zero reference count + assert(s_mmap_page_refcnt[i] == 0 || + (DPORT_PRO_FLASH_MMU_TABLE[i] == entry_val && + DPORT_APP_FLASH_MMU_TABLE[i] == entry_val)); + if (s_mmap_page_refcnt[i] == 0) { + DPORT_PRO_FLASH_MMU_TABLE[i] = entry_val; + DPORT_APP_FLASH_MMU_TABLE[i] = entry_val; + } + ++s_mmap_page_refcnt[i]; + } + + LIST_INSERT_HEAD(&s_mmap_entries_head, new_entry, entries); + new_entry->page = start; + new_entry->count = page_count; + new_entry->handle = ++s_mmap_last_handle; + *out_handle = new_entry->handle; + *out_ptr = (void*) (region_addr + start * FLASH_PAGE_SIZE); + ret = ESP_OK; + } + spi_flash_enable_interrupts_caches_and_other_cpu(); + if (*out_ptr == NULL) { + free(new_entry); + } + return ret; +} + +void IRAM_ATTR spi_flash_munmap(spi_flash_mmap_handle_t handle) +{ + spi_flash_disable_interrupts_caches_and_other_cpu(); + mmap_entry_t* it; + // look for handle in linked list + for (it = LIST_FIRST(&s_mmap_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { + if (it->handle == handle) { + // for each page, decrement reference counter + // if reference count is zero, disable MMU table entry to + // facilitate debugging of use-after-free conditions + for (int i = it->page; i < it->page + it->count; ++i) { + assert(s_mmap_page_refcnt[i] > 0); + if (--s_mmap_page_refcnt[i] == 0) { + DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL; + DPORT_APP_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL; + } + } + LIST_REMOVE(it, entries); + break; + } + } + spi_flash_enable_interrupts_caches_and_other_cpu(); + if (it == NULL) { + assert(0 && "invalid handle, or handle already unmapped"); + } + free(it); +} + +void spi_flash_mmap_dump() +{ + if (s_mmap_page_refcnt[0] == 0) { + spi_flash_mmap_init(); + } + mmap_entry_t* it; + for (it = LIST_FIRST(&s_mmap_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { + printf("handle=%d page=%d count=%d\n", it->handle, it->page, it->count); + } + for (int i = 0; i < REGIONS_COUNT * PAGES_PER_REGION; ++i) { + if (s_mmap_page_refcnt[i] != 0) { + printf("page %d: refcnt=%d paddr=%d\n", + i, (int) s_mmap_page_refcnt[i], DPORT_PRO_FLASH_MMU_TABLE[i]); + } + } +} diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c new file mode 100644 index 0000000000..134e1fe65b --- /dev/null +++ b/components/spi_flash/flash_ops.c @@ -0,0 +1,223 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_ipc.h" +#include "esp_attr.h" +#include "esp_spi_flash.h" +#include "esp_log.h" +#include "cache_utils.h" + +#if CONFIG_SPI_FLASH_ENABLE_COUNTERS +static const char* TAG = "spi_flash"; +static spi_flash_counters_t s_flash_stats; + +#define COUNTER_START() uint32_t ts_begin = xthal_get_ccount() +#define COUNTER_STOP(counter) \ + do{ \ + s_flash_stats.counter.count++; \ + s_flash_stats.counter.time += (xthal_get_ccount() - ts_begin) / (XT_CLOCK_FREQ / 1000000); \ + } while(0) + +#define COUNTER_ADD_BYTES(counter, size) \ + do { \ + s_flash_stats.counter.bytes += size; \ + } while (0) + +#else +#define COUNTER_START() +#define COUNTER_STOP(counter) +#define COUNTER_ADD_BYTES(counter, size) + +#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS + +static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc); + +void spi_flash_init() +{ + spi_flash_init_lock(); +#if CONFIG_SPI_FLASH_ENABLE_COUNTERS + spi_flash_reset_counters(); +#endif +} + +size_t spi_flash_get_chip_size() +{ + return g_rom_flashchip.chip_size; +} + +SpiFlashOpResult IRAM_ATTR spi_flash_unlock() +{ + static bool unlocked = false; + if (!unlocked) { + SpiFlashOpResult rc = SPIUnlock(); + if (rc != SPI_FLASH_RESULT_OK) { + return rc; + } + unlocked = true; + } + return SPI_FLASH_RESULT_OK; +} + +esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) +{ + return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE); +} + +esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) +{ + if (start_addr % SPI_FLASH_SEC_SIZE != 0) { + return ESP_ERR_INVALID_ARG; + } + if (size % SPI_FLASH_SEC_SIZE != 0) { + return ESP_ERR_INVALID_SIZE; + } + if (size + start_addr > spi_flash_get_chip_size()) { + return ESP_ERR_INVALID_SIZE; + } + size_t start = start_addr / SPI_FLASH_SEC_SIZE; + size_t end = start + size / SPI_FLASH_SEC_SIZE; + const size_t sectors_per_block = 16; + COUNTER_START(); + spi_flash_disable_interrupts_caches_and_other_cpu(); + SpiFlashOpResult rc; + rc = spi_flash_unlock(); + if (rc == SPI_FLASH_RESULT_OK) { + for (size_t sector = start; sector != end && rc == SPI_FLASH_RESULT_OK; ) { + if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) { + rc = SPIEraseBlock(sector / sectors_per_block); + sector += sectors_per_block; + COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE); + } + else { + rc = SPIEraseSector(sector); + ++sector; + COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE); + } + } + } + spi_flash_enable_interrupts_caches_and_other_cpu(); + COUNTER_STOP(erase); + return spi_flash_translate_rc(rc); +} + +esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const void *src, size_t size) +{ + // Destination alignment is also checked in ROM code, but we can give + // better error code here + // TODO: add handling of unaligned destinations + if (dest_addr % 4 != 0) { + return ESP_ERR_INVALID_ARG; + } + if (size % 4 != 0) { + return ESP_ERR_INVALID_SIZE; + } + // Out of bound writes are checked in ROM code, but we can give better + // error code here + if (dest_addr + size > g_rom_flashchip.chip_size) { + return ESP_ERR_INVALID_SIZE; + } + COUNTER_START(); + spi_flash_disable_interrupts_caches_and_other_cpu(); + SpiFlashOpResult rc; + rc = spi_flash_unlock(); + if (rc == SPI_FLASH_RESULT_OK) { + rc = SPIWrite((uint32_t) dest_addr, (const uint32_t*) src, (int32_t) size); + COUNTER_ADD_BYTES(write, size); + } + spi_flash_enable_interrupts_caches_and_other_cpu(); + COUNTER_STOP(write); + return spi_flash_translate_rc(rc); +} + +esp_err_t IRAM_ATTR spi_flash_read(size_t src_addr, void *dest, size_t size) +{ + // TODO: replace this check with code which deals with unaligned destinations + if (((ptrdiff_t) dest) % 4 != 0) { + return ESP_ERR_INVALID_ARG; + } + // Source alignment is also checked in ROM code, but we can give + // better error code here + // TODO: add handling of unaligned destinations + if (src_addr % 4 != 0) { + return ESP_ERR_INVALID_ARG; + } + if (size % 4 != 0) { + return ESP_ERR_INVALID_SIZE; + } + // Out of bound reads are checked in ROM code, but we can give better + // error code here + if (src_addr + size > g_rom_flashchip.chip_size) { + return ESP_ERR_INVALID_SIZE; + } + COUNTER_START(); + spi_flash_disable_interrupts_caches_and_other_cpu(); + SpiFlashOpResult rc = SPIRead((uint32_t) src_addr, (uint32_t*) dest, (int32_t) size); + COUNTER_ADD_BYTES(read, size); + spi_flash_enable_interrupts_caches_and_other_cpu(); + COUNTER_STOP(read); + return spi_flash_translate_rc(rc); +} + +static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc) +{ + switch (rc) { + case SPI_FLASH_RESULT_OK: + return ESP_OK; + case SPI_FLASH_RESULT_TIMEOUT: + return ESP_ERR_FLASH_OP_TIMEOUT; + case SPI_FLASH_RESULT_ERR: + default: + return ESP_ERR_FLASH_OP_FAIL; + } +} + +#if CONFIG_SPI_FLASH_ENABLE_COUNTERS + +static inline void dump_counter(spi_flash_counter_t* counter, const char* name) +{ + ESP_LOGI(TAG, "%s count=%8d time=%8dms bytes=%8d\n", name, + counter->count, counter->time, counter->bytes); +} + +const spi_flash_counters_t* spi_flash_get_counters() +{ + return &s_flash_stats; +} + +void spi_flash_reset_counters() +{ + memset(&s_flash_stats, 0, sizeof(s_flash_stats)); +} + +void spi_flash_dump_counters() +{ + dump_counter(&s_flash_stats.read, "read "); + dump_counter(&s_flash_stats.write, "write"); + dump_counter(&s_flash_stats.erase, "erase"); +} + +#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h new file mode 100644 index 0000000000..ae0185dcd7 --- /dev/null +++ b/components/spi_flash/include/esp_partition.h @@ -0,0 +1,242 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP_PARTITION_H__ +#define __ESP_PARTITION_H__ + +#include +#include +#include +#include "esp_err.h" +#include "esp_spi_flash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ESP_PARTITION_TYPE_APP = 0x00, + ESP_PARTITION_TYPE_DATA = 0x01, + ESP_PARTITION_TYPE_FILESYSTEM = 0x02, +} esp_partition_type_t; + +typedef enum { + ESP_PARTITION_SUBTYPE_APP_FACTORY = 0x00, + ESP_PARTITION_SUBTYPE_APP_OTA_MIN = 0x10, + ESP_PARTITION_SUBTYPE_APP_OTA_0 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 0, + ESP_PARTITION_SUBTYPE_APP_OTA_1 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 1, + ESP_PARTITION_SUBTYPE_APP_OTA_2 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 2, + ESP_PARTITION_SUBTYPE_APP_OTA_3 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 3, + ESP_PARTITION_SUBTYPE_APP_OTA_4 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 4, + ESP_PARTITION_SUBTYPE_APP_OTA_5 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 5, + ESP_PARTITION_SUBTYPE_APP_OTA_6 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 6, + ESP_PARTITION_SUBTYPE_APP_OTA_7 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 7, + ESP_PARTITION_SUBTYPE_APP_OTA_8 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 8, + ESP_PARTITION_SUBTYPE_APP_OTA_9 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 9, + ESP_PARTITION_SUBTYPE_APP_OTA_10 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 10, + ESP_PARTITION_SUBTYPE_APP_OTA_11 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 11, + ESP_PARTITION_SUBTYPE_APP_OTA_12 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 12, + ESP_PARTITION_SUBTYPE_APP_OTA_13 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 13, + ESP_PARTITION_SUBTYPE_APP_OTA_14 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 14, + ESP_PARTITION_SUBTYPE_APP_OTA_15 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 15, + ESP_PARTITION_SUBTYPE_APP_OTA_MAX = 15, + ESP_PARTITION_SUBTYPE_APP_TEST = 0x20, + + ESP_PARTITION_SUBTYPE_DATA_OTA = 0x00, + ESP_PARTITION_SUBTYPE_DATA_RF = 0x01, + ESP_PARTITION_SUBTYPE_DATA_NVS = 0x02, + + ESP_PARTITION_SUBTYPE_FILESYSTEM_ESPHTTPD = 0x00, + ESP_PARTITION_SUBTYPE_FILESYSTEM_FAT = 0x01, + ESP_PARTITION_SUBTYPE_FILESYSTEM_SPIFFS = 0x02, + + ESP_PARTITION_SUBTYPE_ANY = 0xff, +} esp_partition_subtype_t; + +#define ESP_PARTITION_SUBTYPE_OTA(i) ((esp_partition_subtype_t)(ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((i) & 0xf))) + + +typedef struct esp_partition_iterator_opaque_* esp_partition_iterator_t; + +typedef struct { + esp_partition_type_t type; + esp_partition_subtype_t subtype; + uint32_t address; + uint32_t size; + char label[17]; + bool encrypted; +} esp_partition_t; + +/** + * @brief Find partition based on one or more parameters + * + * @param type Partition type, one of esp_partition_type_t values + * @param subtype Partition subtype, one of esp_partition_subtype_t values. + * To find all partitions of given type, use + * ESP_PARTITION_SUBTYPE_ANY. + * @param label (optional) Partition label. Set this value if looking + * for partition with a specific name. Pass NULL otherwise. + * + * @return iterator which can be used to enumerate all the partitions found, + * or NULL if no partitions were found. + * Iterator obtained through this function has to be released + * using esp_partition_iterator_release when not used any more. + */ +esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label); + +/** + * @brief Find first partition based on one or more parameters + * + * @param type Partition type, one of esp_partition_type_t values + * @param subtype Partition subtype, one of esp_partition_subtype_t values. + * To find all partitions of given type, use + * ESP_PARTITION_SUBTYPE_ANY. + * @param label (optional) Partition label. Set this value if looking + * for partition with a specific name. Pass NULL otherwise. + * + * @return pointer to esp_partition_t structure, or NULL if no partition is found. + * This pointer is valid for the lifetime of the application. + */ +const esp_partition_t* esp_partition_find_first(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label); + +/** + * @brief Get esp_partition_t structure for given partition + * + * @param iterator Iterator obtained using esp_partition_find. Must be non-NULL. + * + * @return pointer to esp_partition_t structure. This pointer is valid for the lifetime + * of the application. + */ +const esp_partition_t* esp_partition_get(esp_partition_iterator_t iterator); + +/** + * @brief Move partition iterator to the next partition found + * + * Any copies of the iterator will be invalid after this call. + * + * @param iterator Iterator obtained using esp_partition_find. Must be non-NULL. + * + * @return NULL if no partition was found, valid esp_partition_iterator_t otherwise. + */ +esp_partition_iterator_t esp_partition_next(esp_partition_iterator_t iterator); + +/** + * @brief Release partition iterator + * + * @param iterator Iterator obtained using esp_partition_find. Must be non-NULL. + * + */ +void esp_partition_iterator_release(esp_partition_iterator_t iterator); + +/** + * @brief Read data from the partition + * + * @param partition Pointer to partition structure obtained using + * esp_partition_find_first or esp_partition_get. + * Must be non-NULL. + * @param dst Pointer to the buffer where data should be stored. + * Pointer must be non-NULL and buffer must be at least 'size' bytes long. + * @param src_offset Address of the data to be read, relative to the + * beginning of the partition. + * @param size Size of data to be read, in bytes. + * + * @return ESP_OK, if data was read successfully; + * ESP_ERR_INVALID_ARG, if src_offset exceeds partition size; + * ESP_ERR_INVALID_SIZE, if read would go out of bounds of the partition; + * or one of error codes from lower-level flash driver. + */ +esp_err_t esp_partition_read(const esp_partition_t* partition, + size_t src_offset, void* dst, size_t size); + +/** + * @brief Write data to the partition + * + * Before writing data to flash, corresponding region of flash needs to be erased. + * This can be done using esp_partition_erase_range function. + * + * @param partition Pointer to partition structure obtained using + * esp_partition_find_first or esp_partition_get. + * Must be non-NULL. + * @param dst_offset Address where the data should be written, relative to the + * beginning of the partition. + * @param src Pointer to the source buffer. Pointer must be non-NULL and + * buffer must be at least 'size' bytes long. + * @param size Size of data to be written, in bytes. + * + * @note Prior to writing to flash memory, make sure it has been erased with + * esp_partition_erase_range call. + * + * @return ESP_OK, if data was written successfully; + * ESP_ERR_INVALID_ARG, if dst_offset exceeds partition size; + * ESP_ERR_INVALID_SIZE, if write would go out of bounds of the partition; + * or one of error codes from lower-level flash driver. + */ +esp_err_t esp_partition_write(const esp_partition_t* partition, + size_t dst_offset, const void* src, size_t size); + +/** + * @brief Erase part of the partition + * + * @param partition Pointer to partition structure obtained using + * esp_partition_find_first or esp_partition_get. + * Must be non-NULL. + * @param start_addr Address where erase operation should start. Must be aligned + * to 4 kilobytes. + * @param size Size of the range which should be erased, in bytes. + * Must be divisible by 4 kilobytes. + * + * @return ESP_OK, if the range was erased successfully; + * ESP_ERR_INVALID_ARG, if iterator or dst are NULL; + * ESP_ERR_INVALID_SIZE, if erase would go out of bounds of the partition; + * or one of error codes from lower-level flash driver. + */ +esp_err_t esp_partition_erase_range(const esp_partition_t* partition, + uint32_t start_addr, uint32_t size); + +/** + * @brief Configure MMU to map partition into data memory + * + * Unlike spi_flash_mmap function, which requires a 64kB aligned base address, + * this function doesn't impose such a requirement. + * If offset results in a flash address which is not aligned to 64kB boundary, + * address will be rounded to the lower 64kB boundary, so that mapped region + * includes requested range. + * Pointer returned via out_ptr argument will be adjusted to point to the + * requested offset (not necessarily to the beginning of mmap-ed region). + * + * To release mapped memory, pass handle returned via out_handle argument to + * spi_flash_munmap function. + * + * @param partition Pointer to partition structure obtained using + * esp_partition_find_first or esp_partition_get. + * Must be non-NULL. + * @param offset Offset from the beginning of partition where mapping should start. + * @param size Size of the area to be mapped. + * @param memory Memory space where the region should be mapped + * @param out_ptr Output, pointer to the mapped memory region + * @param out_handle Output, handle which should be used for spi_flash_munmap call + * + * @return ESP_OK, if successful + */ +esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset, uint32_t size, + spi_flash_mmap_memory_t memory, + const void** out_ptr, spi_flash_mmap_handle_t* out_handle); + + +#ifdef __cplusplus +} +#endif + + +#endif /* __ESP_PARTITION_H__ */ diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 6d635880eb..840bbc4971 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -16,6 +16,7 @@ #define ESP_SPI_FLASH_H #include +#include #include "esp_err.h" #include "sdkconfig.h" @@ -34,41 +35,126 @@ extern "C" { * * This function must be called exactly once, before any other * spi_flash_* functions are called. + * Currently this function is called from startup code. There is + * no need to call it from application code. * */ void spi_flash_init(); +/** + * @brief Get flash chip size, as set in binary image header + * + * @note This value does not necessarily match real flash size. + * + * @return size of flash chip, in bytes + */ +size_t spi_flash_get_chip_size(); + /** * @brief Erase the Flash sector. * - * @param uint16 sec : Sector number, the count starts at sector 0, 4KB per sector. + * @param sector Sector number, the count starts at sector 0, 4KB per sector. * * @return esp_err_t */ -esp_err_t spi_flash_erase_sector(uint16_t sec); +esp_err_t spi_flash_erase_sector(size_t sector); + +/** + * @brief Erase a range of flash sectors + * + * @param uint32_t start_address : Address where erase operation has to start. + * Must be 4kB-aligned + * @param uint32_t size : Size of erased range, in bytes. Must be divisible by 4kB. + * + * @return esp_err_t + */ +esp_err_t spi_flash_erase_range(size_t start_addr, size_t size); + /** * @brief Write data to Flash. * - * @param uint32 des_addr : destination address in Flash. - * @param uint32 *src_addr : source address of the data. - * @param uint32 size : length of data + * @note Address in flash, dest, has to be 4-byte aligned. + * This is a temporary limitation which will be removed. + * + * @param dest destination address in Flash + * @param src pointer to the source buffer + * @param size length of data, in bytes * * @return esp_err_t */ -esp_err_t spi_flash_write(uint32_t des_addr, const uint32_t *src_addr, uint32_t size); +esp_err_t spi_flash_write(size_t dest, const void *src, size_t size); /** * @brief Read data from Flash. * - * @param uint32 src_addr : source address of the data in Flash. - * @param uint32 *des_addr : destination address. - * @param uint32 size : length of data + * @note Both src and dest have to be 4-byte aligned. + * This is a temporary limitation which will be removed. + * + * @param src source address of the data in Flash. + * @param dest pointer to the destination buffer + * @param size length of data * * @return esp_err_t */ -esp_err_t spi_flash_read(uint32_t src_addr, uint32_t *des_addr, uint32_t size); +esp_err_t spi_flash_read(size_t src, void *dest, size_t size); +/** + * @brief Enumeration which specifies memory space requested in an mmap call + */ +typedef enum { + SPI_FLASH_MMAP_DATA, /**< map to data memory (Vaddr0), allows byte-aligned access, 4 MB total */ + SPI_FLASH_MMAP_INST, /**< map to instruction memory (Vaddr1-3), allows only 4-byte-aligned access, 11 MB total */ +} spi_flash_mmap_memory_t; + +/** + * @brief Opaque handle for memory region obtained from spi_flash_mmap. + */ +typedef uint32_t spi_flash_mmap_handle_t; + +/** + * @brief Map region of flash memory into data or instruction address space + * + * This function allocates sufficient number of 64k MMU pages and configures + * them to map request region of flash memory into data address space or into + * instruction address space. It may reuse MMU pages which already provide + * required mapping. As with any allocator, there is possibility of fragmentation + * of address space if mmap/munmap are heavily used. To troubleshoot issues with + * page allocation, use spi_flash_mmap_dump function. + * + * @param src_addr Physical address in flash where requested region starts. + * This address *must* be aligned to 64kB boundary. + * @param size Size of region which has to be mapped. This size will be rounded + * up to a 64k boundary. + * @param memory Memory space where the region should be mapped + * @param out_ptr Output, pointer to the mapped memory region + * @param out_handle Output, handle which should be used for spi_flash_munmap call + * + * @return ESP_OK on success, ESP_ERR_NO_MEM if pages can not be allocated + */ +esp_err_t spi_flash_mmap(uint32_t src_addr, size_t size, spi_flash_mmap_memory_t memory, + const void** out_ptr, spi_flash_mmap_handle_t* out_handle); + +/** + * @brief Release region previously obtained using spi_flash_mmap + * + * @note Calling this function will not necessarily unmap memory region. + * Region will only be unmapped when there are no other handles which + * reference this region. In case of partially overlapping regions + * it is possible that memory will be unmapped partially. + * + * @param handle Handle obtained from spi_flash_mmap + */ +void spi_flash_munmap(spi_flash_mmap_handle_t handle); + +/** + * @brief Display information about mapped regions + * + * This function lists handles obtained using spi_flash_mmap, along with range + * of pages allocated to each handle. It also lists all non-zero entries of + * MMU table and corresponding reference counts. + */ +void spi_flash_mmap_dump(); #if CONFIG_SPI_FLASH_ENABLE_COUNTERS @@ -78,7 +164,7 @@ esp_err_t spi_flash_read(uint32_t src_addr, uint32_t *des_addr, uint32_t size); typedef struct { uint32_t count; // number of times operation was executed uint32_t time; // total time taken, in microseconds - uint32_t bytes; // total number of bytes, for read and write operations + uint32_t bytes; // total number of bytes } spi_flash_counter_t; typedef struct { diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c new file mode 100644 index 0000000000..21013d96fa --- /dev/null +++ b/components/spi_flash/partition.c @@ -0,0 +1,269 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include +#include + +#include "esp_attr.h" +#include "esp_flash_data_types.h" +#include "esp_spi_flash.h" +#include "esp_partition.h" +#include "esp_log.h" + + +#ifndef NDEBUG +// Enable built-in checks in queue.h in debug builds +#define INVARIANTS +#endif +#include "rom/queue.h" + + +typedef struct partition_list_item_ { + esp_partition_t info; + SLIST_ENTRY(partition_list_item_) next; +} partition_list_item_t; + +typedef struct esp_partition_iterator_opaque_ { + esp_partition_type_t type; // requested type + esp_partition_subtype_t subtype; // requested subtype + const char* label; // requested label (can be NULL) + partition_list_item_t* next_item; // next item to iterate to + esp_partition_t* info; // pointer to info (it is redundant, but makes code more readable) +} esp_partition_iterator_opaque_t; + + +static esp_partition_iterator_opaque_t* iterator_create(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label); +static esp_err_t load_partitions(); + + +static SLIST_HEAD(partition_list_head_, partition_list_item_) s_partition_list = + SLIST_HEAD_INITIALIZER(s_partition_list); +static _lock_t s_partition_list_lock; + + +esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, + esp_partition_subtype_t subtype, const char* label) +{ + if (SLIST_EMPTY(&s_partition_list)) { + // only lock if list is empty (and check again after acquiring lock) + _lock_acquire(&s_partition_list_lock); + esp_err_t err = ESP_OK; + if (SLIST_EMPTY(&s_partition_list)) { + err = load_partitions(); + } + _lock_release(&s_partition_list_lock); + if (err != ESP_OK) { + return NULL; + } + } + // create an iterator pointing to the start of the list + // (next item will be the first one) + esp_partition_iterator_t it = iterator_create(type, subtype, label); + // advance iterator to the next item which matches constraints + it = esp_partition_next(it); + // if nothing found, it == NULL and iterator has been released + return it; +} + +esp_partition_iterator_t esp_partition_next(esp_partition_iterator_t it) +{ + assert(it); + // iterator reached the end of linked list? + if (it->next_item == NULL) { + return NULL; + } + _lock_acquire(&s_partition_list_lock); + for (; it->next_item != NULL; it->next_item = SLIST_NEXT(it->next_item, next)) { + esp_partition_t* p = &it->next_item->info; + if (it->type != p->type) { + continue; + } + if (it->subtype != 0xff && it->subtype != p->subtype) { + continue; + } + if (it->label != NULL && strcmp(it->label, p->label) != 0) { + continue; + } + // all constraints match, bail out + break; + } + _lock_release(&s_partition_list_lock); + if (it->next_item == NULL) { + esp_partition_iterator_release(it); + return NULL; + } + it->info = &it->next_item->info; + it->next_item = SLIST_NEXT(it->next_item, next); + return it; +} + +const esp_partition_t* esp_partition_find_first(esp_partition_type_t type, + esp_partition_subtype_t subtype, const char* label) +{ + esp_partition_iterator_t it = esp_partition_find(type, subtype, label); + if (it == NULL) { + return NULL; + } + const esp_partition_t* res = esp_partition_get(it); + esp_partition_iterator_release(it); + return res; +} + +static esp_partition_iterator_opaque_t* iterator_create(esp_partition_type_t type, + esp_partition_subtype_t subtype, const char* label) +{ + esp_partition_iterator_opaque_t* it = + (esp_partition_iterator_opaque_t*) malloc(sizeof(esp_partition_iterator_opaque_t)); + it->type = type; + it->subtype = subtype; + it->label = label; + it->next_item = SLIST_FIRST(&s_partition_list); + it->info = NULL; + return it; +} + +// Create linked list of partition_list_item_t structures. +// This function is called only once, with s_partition_list_lock taken. +static esp_err_t load_partitions() +{ + const uint32_t* ptr; + spi_flash_mmap_handle_t handle; + // map 64kB block where partition table is located + esp_err_t err = spi_flash_mmap(ESP_PARTITION_TABLE_ADDR & 0xffff0000, + SPI_FLASH_SEC_SIZE, SPI_FLASH_MMAP_DATA, (const void**) &ptr, &handle); + if (err != ESP_OK) { + return err; + } + // calculate partition address within mmap-ed region + const esp_partition_info_t* it = (const esp_partition_info_t*) + (ptr + (ESP_PARTITION_TABLE_ADDR & 0xffff) / sizeof(*ptr)); + const esp_partition_info_t* end = it + SPI_FLASH_SEC_SIZE / sizeof(*it); + // tail of the linked list of partitions + partition_list_item_t* last = NULL; + for (; it != end; ++it) { + if (it->magic != ESP_PARTITION_MAGIC) { + break; + } + // allocate new linked list item and populate it with data from partition table + partition_list_item_t* item = (partition_list_item_t*) malloc(sizeof(partition_list_item_t)); + item->info.address = it->pos.offset; + item->info.size = it->pos.size; + item->info.type = it->type; + item->info.subtype = it->subtype; + item->info.encrypted = false; + // it->label may not be zero-terminated + strncpy(item->info.label, (const char*) it->label, sizeof(it->label)); + item->info.label[sizeof(it->label)] = 0; + // add it to the list + if (last == NULL) { + SLIST_INSERT_HEAD(&s_partition_list, item, next); + } else { + SLIST_INSERT_AFTER(last, item, next); + } + } + spi_flash_munmap(handle); + return ESP_OK; +} + +void esp_partition_iterator_release(esp_partition_iterator_t iterator) +{ + // iterator == NULL is okay + free(iterator); +} + +const esp_partition_t* esp_partition_get(esp_partition_iterator_t iterator) +{ + assert(iterator != NULL); + return iterator->info; +} + +esp_err_t esp_partition_read(const esp_partition_t* partition, + size_t src_offset, void* dst, size_t size) +{ + assert(partition != NULL); + if (src_offset > partition->size) { + return ESP_ERR_INVALID_ARG; + } + if (src_offset + size > partition->size) { + return ESP_ERR_INVALID_SIZE; + } + return spi_flash_read(partition->address + src_offset, dst, size); +} + +esp_err_t esp_partition_write(const esp_partition_t* partition, + size_t dst_offset, const void* src, size_t size) +{ + assert(partition != NULL); + if (dst_offset > partition->size) { + return ESP_ERR_INVALID_ARG; + } + if (dst_offset + size > partition->size) { + return ESP_ERR_INVALID_SIZE; + } + return spi_flash_write(partition->address + dst_offset, src, size); +} + +esp_err_t esp_partition_erase_range(const esp_partition_t* partition, + size_t start_addr, size_t size) +{ + assert(partition != NULL); + if (start_addr > partition->size) { + return ESP_ERR_INVALID_ARG; + } + if (start_addr + size > partition->size) { + return ESP_ERR_INVALID_SIZE; + } + if (size % SPI_FLASH_SEC_SIZE != 0) { + return ESP_ERR_INVALID_SIZE; + } + if (start_addr % SPI_FLASH_SEC_SIZE != 0) { + return ESP_ERR_INVALID_ARG; + } + return spi_flash_erase_range(partition->address + start_addr, size); + +} + +/* + * Note: current implementation ignores the possibility of multiple regions in the same partition being + * mapped. Reference counting and address space re-use is delegated to spi_flash_mmap. + * + * If this becomes a performance issue (i.e. if we need to map multiple regions within the partition), + * we can add esp_partition_mmapv which will accept an array of offsets and sizes, and return array of + * mmaped pointers, and a single handle for all these regions. + */ +esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset, uint32_t size, + spi_flash_mmap_memory_t memory, + const void** out_ptr, spi_flash_mmap_handle_t* out_handle) +{ + assert(partition != NULL); + if (offset > partition->size) { + return ESP_ERR_INVALID_ARG; + } + if (offset + size > partition->size) { + return ESP_ERR_INVALID_SIZE; + } + size_t phys_addr = partition->address + offset; + // offset within 64kB block + size_t region_offset = phys_addr & 0xffff; + size_t mmap_addr = phys_addr & 0xffff0000; + esp_err_t rc = spi_flash_mmap(mmap_addr, size, memory, out_ptr, out_handle); + // adjust returned pointer to point to the correct offset + if (rc == ESP_OK) { + *out_ptr = (void*) (((ptrdiff_t) *out_ptr) + region_offset); + } + return rc; +} diff --git a/components/spi_flash/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c new file mode 100644 index 0000000000..36e5bf8236 --- /dev/null +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -0,0 +1,78 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 "rom/spi_flash.h" +#include "soc/spi_reg.h" + +static const uint32_t STATUS_QIE_BIT = (1 << 9); /* Quad Enable */ + +#define SPI_IDX 1 +#define OTH_IDX 0 + +#ifndef BOOTLOADER_BUILD +#define ATTR IRAM_ATTR +#else +#define ATTR +#endif // BOOTLOADER_BUILD + +extern SpiFlashChip SPI_flashchip_data; + +static void ATTR Wait_SPI_Idle(void) +{ + /* Wait for SPI state machine to be idle */ + while((REG_READ(SPI_EXT2_REG(SPI_IDX)) & SPI_ST)) { + } + while(REG_READ(SPI_EXT2_REG(OTH_IDX)) & SPI_ST) { + } +} + +/* Modified version of SPIUnlock() that replaces version in ROM. + + This works around a bug where SPIUnlock sometimes reads the wrong + high status byte (RDSR2 result) and then copies it back to the + flash status, which can cause the CMP bit or Status Register + Protect bit to become set. + + Like other ROM SPI functions, this function is not designed to be + called directly from an RTOS environment without taking precautions + about interrupts, CPU coordination, flash mapping. However some of + the functions in esp_spi_flash.c call it. + */ +SpiFlashOpResult ATTR SPIUnlock(void) +{ + uint32_t status; + + Wait_SPI_Idle(); + + if (SPI_read_status_high(&status) != SPI_FLASH_RESULT_OK) { + return SPI_FLASH_RESULT_ERR; + } + + /* Clear all bits except QIE, if it is set. + (This is different from ROM SPIUnlock, which keeps all bits as-is.) + */ + status &= STATUS_QIE_BIT; + + Wait_SPI_Idle(); + REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN); + while(REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { + } + Wait_SPI_Idle(); + + SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); + if (SPI_write_status(&SPI_flashchip_data, status) != SPI_FLASH_RESULT_OK) { + return SPI_FLASH_RESULT_ERR; + } + + return SPI_FLASH_RESULT_OK; +} diff --git a/components/tcpip_adapter/component.mk b/components/tcpip_adapter/component.mk index a57ae0b12b..c2c4c03a1a 100755 --- a/components/tcpip_adapter/component.mk +++ b/components/tcpip_adapter/component.mk @@ -1,5 +1,5 @@ # # Component Makefile # +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) -include $(IDF_PATH)/make/component_common.mk diff --git a/components/tcpip_adapter/include/tcpip_adapter.h b/components/tcpip_adapter/include/tcpip_adapter.h index 5b0fc4c627..45d6ade305 100644 --- a/components/tcpip_adapter/include/tcpip_adapter.h +++ b/components/tcpip_adapter/include/tcpip_adapter.h @@ -67,11 +67,15 @@ typedef struct { typedef dhcps_lease_t tcpip_adapter_dhcps_lease_t; #if CONFIG_DHCP_STA_LIST -struct station_list { - STAILQ_ENTRY(station_list) next; +typedef struct { uint8_t mac[6]; ip4_addr_t ip; -}; +}tcpip_adapter_sta_info_t; + +typedef struct { + tcpip_adapter_sta_info_t sta[ESP_WIFI_MAX_CONN_NUM]; + int num; +}tcpip_adapter_sta_list_t; #endif #endif @@ -359,26 +363,27 @@ wifi_interface_t tcpip_adapter_get_wifi_if(void *dev); /** * @brief Get the station information list * - * @note This function should be called in AP mode and dhcp server started, and the list should - * be by using tcpip_adapter_free_sta_list. - * - * @param[in] sta_info: station information - * @param[out] sta_list: station information list + * @param[in] wifi_sta_list_t *wifi_sta_list: station list info + * @param[out] tcpip_adapter_sta_list_t *tcpip_sta_list: station list info * * @return ESP_OK * ESP_ERR_TCPIP_ADAPTER_NO_MEM * ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS */ -esp_err_t tcpip_adapter_get_sta_list(struct station_info *sta_info, struct station_list **sta_list); +esp_err_t tcpip_adapter_get_sta_list(wifi_sta_list_t *wifi_sta_list, tcpip_adapter_sta_list_t *tcpip_sta_list); +#define TCPIP_HOSTNAME_MAX_SIZE 31 /** - * @brief Free the station information list's memory + * @brief Set the hostname to the interface * - * @param sta_list: station information list + * @param[in] tcpip_if: the interface which we will set the hostname + * @param[in] hostname: the host name for set the interfce * - * @return ESP_OK + * @return ESP_OK:success + * ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY:interface status error + * ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS:parameter error */ -esp_err_t tcpip_adapter_free_sta_list(struct station_list *sta_list); +esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *hostname); #ifdef __cplusplus } diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 78fecf2cbf..3edc90509e 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -103,7 +103,9 @@ esp_err_t tcpip_adapter_stop(tcpip_adapter_if_t tcpip_if) if (tcpip_if == TCPIP_ADAPTER_IF_AP) { dhcps_stop(esp_netif[tcpip_if]); // TODO: dhcps checks status by its self - dhcps_status = TCPIP_ADAPTER_DHCP_INIT; + if (TCPIP_ADAPTER_DHCP_STOPPED != dhcps_status){ + dhcps_status = TCPIP_ADAPTER_DHCP_INIT; + } } else if (tcpip_if == TCPIP_ADAPTER_IF_STA) { dhcp_release(esp_netif[tcpip_if]); dhcp_stop(esp_netif[tcpip_if]); @@ -588,48 +590,49 @@ wifi_interface_t tcpip_adapter_get_wifi_if(void *dev) return WIFI_IF_MAX; } -esp_err_t tcpip_adapter_get_sta_list(struct station_info *sta_info, struct station_list **sta_list) +esp_err_t tcpip_adapter_get_sta_list(wifi_sta_list_t *wifi_sta_list, tcpip_adapter_sta_list_t *tcpip_sta_list) { - struct station_info *info = sta_info; - struct station_list *list; - STAILQ_HEAD(, station_list) list_head; + int i; - if (sta_list == NULL) + if ((wifi_sta_list == NULL) || (tcpip_sta_list == NULL)) return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; - STAILQ_INIT(&list_head); - - while (info != NULL) { - list = (struct station_list *)malloc(sizeof(struct station_list)); - memset(list, 0, sizeof (struct station_list)); - - if (list == NULL) { - return ESP_ERR_TCPIP_ADAPTER_NO_MEM; - } - - memcpy(list->mac, info->bssid, 6); - dhcp_search_ip_on_mac(list->mac, &list->ip); - STAILQ_INSERT_TAIL(&list_head, list, next); - - info = STAILQ_NEXT(info, next); + memset(tcpip_sta_list, 0, sizeof(tcpip_adapter_sta_list_t)); + tcpip_sta_list->num = wifi_sta_list->num; + for (i=0; inum; i++){ + memcpy(tcpip_sta_list->sta[i].mac, wifi_sta_list->sta[i].mac, 6); + dhcp_search_ip_on_mac(tcpip_sta_list->sta[i].mac, &tcpip_sta_list->sta[i].ip); } - *sta_list = STAILQ_FIRST(&list_head); - return ESP_OK; } -esp_err_t tcpip_adapter_free_sta_list(struct station_list *sta_list) +esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *hostname) { - struct station_list *list = sta_list; + struct netif *p_netif; + static char hostinfo[TCPIP_HOSTNAME_MAX_SIZE + 1]; - while (sta_list != NULL) { - list = sta_list; - sta_list = STAILQ_NEXT(sta_list, next); - free(list); + if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || hostname == NULL) { + return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; } - return ESP_OK; + if (strlen(hostname) >= TCPIP_HOSTNAME_MAX_SIZE) { + return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; + } + + p_netif = esp_netif[tcpip_if]; + if (p_netif != NULL) { + if (netif_is_up(p_netif)) { + return ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY; + } else { + memset(hostinfo, 0, sizeof(hostinfo)); + memcpy(hostinfo, hostname, strlen(hostname)); + p_netif->hostname = hostinfo; + return ESP_OK; + } + } else { + return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; + } } #endif diff --git a/components/vfs/README.rst b/components/vfs/README.rst new file mode 100644 index 0000000000..c58161c900 --- /dev/null +++ b/components/vfs/README.rst @@ -0,0 +1,128 @@ +Virtual filesystem component +============================ + +Overview +-------- + +Virtual filesystem (VFS) component provides a unified interface for drivers which can perform operations on file-like objects. This can be a real filesystems (FAT, SPIFFS, etc.), or device drivers which exposes file-like interface. + +This component allows C library functions, such as fopen and fprintf, to work with FS drivers. At high level, each FS driver is associated with some path prefix. When one of C library functions needs to open a file, VFS component searches for the FS driver associated with the file's path, and forwards the call to that driver. VFS also forwards read, write, and other calls for the given file to the same FS driver. + +For example, one can register a FAT filesystem driver with ``/fat`` prefix, and call ``fopen("/fat/file.txt", "w")``. VFS component will then call ``open`` function of FAT driver and pass ``/file.txt`` argument to it (and appropriate mode flags). All subsequent calls to C library functions for the returned ``FILE*`` stream will also be forwarded to the FAT driver. + +FS registration +--------------- + +To register an FS driver, application needs to define in instance of esp_vfs_t structure and populate it with function pointers to FS APIs:: + + esp_vfs_t myfs = { + .fd_offset = 0, + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &myfs_write, + .open = &myfs_open, + .fstat = &myfs_fstat, + .close = &myfs_close, + .read = &myfs_read, + .lseek = NULL, + .stat = NULL, + .link = NULL, + .unlink = NULL, + .rename = NULL + }; + + ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL)); + +Depending on the way FS driver declares its APIs, either ``read``, ``write``, etc., or ``read_p``, ``write_p``, etc. should be used. + +Case 1: API functions are declared without an extra context pointer (FS driver is a singleton):: + + size_t myfs_write(int fd, const void * data, size_t size); + + // In definition of esp_vfs_t: + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &myfs_write, + // ... other members initialized + + // When registering FS, context pointer (third argument) is NULL: + ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL)); + +Case 2: API functions are declared with an extra context pointer (FS driver supports multiple instances):: + + size_t myfs_write(myfs_t* fs, int fd, const void * data, size_t size); + + // In definition of esp_vfs_t: + .flags = ESP_VFS_FLAG_CONTEXT_PTR, + .write_p = &myfs_write, + // ... other members initialized + + // When registering FS, pass the FS context pointer into the third argument + // (hypothetical myfs_mount function is used for illustrative purposes) + myfs_t* myfs_inst1 = myfs_mount(partition1->offset, partition1->size); + ESP_ERROR_CHECK(esp_vfs_register("/data1", &myfs, myfs_inst1)); + + // Can register another instance: + myfs_t* myfs_inst2 = myfs_mount(partition2->offset, partition2->size); + ESP_ERROR_CHECK(esp_vfs_register("/data2", &myfs, myfs_inst2)); + +Paths +----- + +Each registered FS has a path prefix associated with it. This prefix may be considered a "mount point" of this partition. + +Registering mount points which have another mount point as a prefix is not supported and results in undefined behavior. For instance, the following is correct and supported: + +- FS 1 on /data/fs1 +- FS 2 on /data/fs2 + +This **will not work** as expected: + +- FS 1 on /data +- FS 2 on /data/fs2 + +When opening files, FS driver will only be given relative path to files. For example: + +- ``myfs`` driver is registered with ``/data`` as path prefix +- and application calls ``fopen("/data/config.json", ...)`` +- then VFS component will call ``myfs_open("/config.json", ...)``. +- ``myfs`` driver will open ``/config.json`` file + +VFS doesn't impose a limit on total file path length, but it does limit FS path prefix to ``ESP_VFS_PATH_MAX`` characters. Individual FS drivers may have their own filename length limitations. + + +File descriptors +---------------- + +It is suggested that filesystem drivers should use small positive integers as file descriptors. VFS component assumes that ``CONFIG_MAX_FD_BITS`` bits (12 by default) are sufficient to represent a file descriptor. + +If filesystem is configured with an option to offset all file descriptors by a constant value, such value should be passed to ``fd_offset`` field of ``esp_vfs_t`` structure. VFS component will then remove this offset when working with FDs of that specific FS, bringing them into the range of small positive integers. + +While file descriptors returned by VFS component to newlib library are rarely seen by the application, the following details may be useful for debugging purposes. File descriptors returned by VFS component are composed of two parts: FS driver ID, and the actual file descriptor. Because newlib stores file descriptors as 16-bit integers, VFS component is also limited by 16 bits to store both parts. + +Lower ``CONFIG_MAX_FD_BITS`` bits are used to store zero-based file descriptor. If FS driver has a non-zero ``fd_offset`` field, this ``fd_offset`` is subtracted FDs obtained from the FS ``open`` call, and the result is stored in the lower bits of the FD. Higher bits are used to save the index of FS in the internal table of registered filesystems. + +When VFS component receives a call from newlib which has a file descriptor, this file descriptor is translated back to the FS-specific file descriptor. First, higher bits of FD are used to identify the FS. Then ``fd_offset`` field of the FS is added to the lower ``CONFIG_MAX_FD_BITS`` bits of the fd, and resulting FD is passed to the FS driver. + +:: + + FD as seen by newlib FD as seen by FS driver + +-----+ + +-------+---------------+ | | +------------------------+ + | FS id | Zero—based FD | +---------------> sum +----> | + +---+---+------+--------+ | | | +------------------------+ + | | | +--^--+ + | +--------------+ | + | | + | +-------------+ | + | | Table of | | + | | registered | | + | | filesystems | | + | +-------------+ +-------------+ | + +-------> entry +----> esp_vfs_t | | + index +-------------+ | structure | | + | | | | | + | | | + fd_offset +---+ + +-------------+ | | + +-------------+ + + + diff --git a/components/vfs/component.mk b/components/vfs/component.mk new file mode 100755 index 0000000000..c2c4c03a1a --- /dev/null +++ b/components/vfs/component.mk @@ -0,0 +1,5 @@ +# +# Component Makefile +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h new file mode 100644 index 0000000000..2d9e52c5af --- /dev/null +++ b/components/vfs/include/esp_vfs.h @@ -0,0 +1,157 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP_VFS_H__ +#define __ESP_VFS_H__ + +#include +#include +#include "esp_err.h" +#include +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Maximum length of path prefix (not including zero terminator) + */ +#define ESP_VFS_PATH_MAX 15 + +/** + * Default value of flags member in esp_vfs_t structure. + */ +#define ESP_VFS_FLAG_DEFAULT 0 + +/** + * Flag which indicates that FS needs extra context pointer in syscalls. + */ +#define ESP_VFS_FLAG_CONTEXT_PTR 1 + +/** + * @brief VFS definition structure + * + * This structure should be filled with pointers to corresponding + * FS driver functions. + * + * If the FS implementation has an option to use certain offset for + * all file descriptors, this value should be passed into fd_offset + * field. Otherwise VFS component will translate all FDs to start + * at zero offset. + * + * Some FS implementations expect some state (e.g. pointer to some structure) + * to be passed in as a first argument. For these implementations, + * populate the members of this structure which have _p suffix, set + * flags member to ESP_VFS_FLAG_CONTEXT_PTR and provide the context pointer + * to esp_vfs_register function. + * If the implementation doesn't use this extra argument, populate the + * members without _p suffix and set flags memeber to ESP_VFS_FLAG_DEFAULT. + * + * If the FS driver doesn't provide some of the functions, set corresponding + * members to NULL. + */ +typedef struct +{ + int fd_offset; + int flags; + union { + size_t (*write_p)(void* p, int fd, const void * data, size_t size); + size_t (*write)(int fd, const void * data, size_t size); + }; + union { + off_t (*lseek_p)(void* p, int fd, off_t size, int mode); + off_t (*lseek)(int fd, off_t size, int mode); + }; + union { + ssize_t (*read_p)(void* ctx, int fd, void * dst, size_t size); + ssize_t (*read)(int fd, void * dst, size_t size); + }; + union { + int (*open_p)(void* ctx, const char * path, int flags, int mode); + int (*open)(const char * path, int flags, int mode); + }; + union { + int (*close_p)(void* ctx, int fd); + int (*close)(int fd); + }; + union { + int (*fstat_p)(void* ctx, int fd, struct stat * st); + int (*fstat)(int fd, struct stat * st); + }; + union { + int (*stat_p)(void* ctx, const char * path, struct stat * st); + int (*stat)(const char * path, struct stat * st); + }; + union { + int (*link_p)(void* ctx, const char* n1, const char* n2); + int (*link)(const char* n1, const char* n2); + }; + union { + int (*unlink_p)(void* ctx, const char *path); + int (*unlink)(const char *path); + }; + union { + int (*rename_p)(void* ctx, const char *src, const char *dst); + int (*rename)(const char *src, const char *dst); + }; +} esp_vfs_t; + + +/** + * Register a virtual filesystem for given path prefix. + * + * @param base_path file path prefix associated with the filesystem. + * Must be a zero-terminated C string, up to ESP_VFS_PATH_MAX + * characters long, and at least 2 characters long. + * Name must start with a "/" and must not end with "/". + * For example, "/data" or "/dev/spi" are valid. + * These VFSes would then be called to handle file paths such as + * "/data/myfile.txt" or "/dev/spi/0". + * @param vfs Pointer to esp_vfs_t, a structure which maps syscalls to + * the filesystem driver functions. VFS component doesn't + * assume ownership of this pointer. + * @param ctx If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer + * which should be passed to VFS functions. Otherwise, NULL. + * + * @return ESP_OK if successful, ESP_ERR_NO_MEM if too many VFSes are + * registered. + */ +esp_err_t esp_vfs_register(const char* base_path, const esp_vfs_t* vfs, void* ctx); + + +/** + * These functions are to be used in newlib syscall table. They will be called by + * newlib when it needs to use any of the syscalls. + */ + +ssize_t esp_vfs_write(struct _reent *r, int fd, const void * data, size_t size); +off_t esp_vfs_lseek(struct _reent *r, int fd, off_t size, int mode); +ssize_t esp_vfs_read(struct _reent *r, int fd, void * dst, size_t size); +int esp_vfs_open(struct _reent *r, const char * path, int flags, int mode); +int esp_vfs_close(struct _reent *r, int fd); +int esp_vfs_fstat(struct _reent *r, int fd, struct stat * st); +int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st); +int esp_vfs_link(struct _reent *r, const char* n1, const char* n2); +int esp_vfs_unlink(struct _reent *r, const char *path); +int esp_vfs_rename(struct _reent *r, const char *src, const char *dst); + + + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif //__ESP_VFS_H__ diff --git a/components/vfs/include/esp_vfs_dev.h b/components/vfs/include/esp_vfs_dev.h new file mode 100644 index 0000000000..bb2579ee0a --- /dev/null +++ b/components/vfs/include/esp_vfs_dev.h @@ -0,0 +1,28 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 __ESP_VFS_DEV_H__ +#define __ESP_VFS_DEV_H__ + +#include "esp_vfs.h" + +/** + * @brief add /dev/uart virtual filesystem driver + * + * This function is called from startup code to enable serial output + */ +void esp_vfs_dev_uart_register(); + + +#endif //__ESP_VFS_DEV_H__ diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c new file mode 100644 index 0000000000..b60c60a818 --- /dev/null +++ b/components/vfs/vfs.c @@ -0,0 +1,289 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include +#include +#include "esp_vfs.h" +#include "esp_log.h" + +/* + * File descriptors visible by the applications are composed of two parts. + * Lower CONFIG_MAX_FD_BITS bits are used for the actual file descriptor. + * Next (16 - CONFIG_MAX_FD_BITS - 1) bits are used to identify the VFS this + * descriptor corresponds to. + * Highest bit is zero. + * We can only use 16 bits because newlib stores file descriptor as short int. + */ + +#ifndef CONFIG_MAX_FD_BITS +#define CONFIG_MAX_FD_BITS 12 +#endif + +#define MAX_VFS_ID_BITS (16 - CONFIG_MAX_FD_BITS - 1) +// mask of actual file descriptor (e.g. 0x00000fff) +#define VFS_FD_MASK ((1 << CONFIG_MAX_FD_BITS) - 1) +// max number of VFS entries +#define VFS_MAX_COUNT ((1 << MAX_VFS_ID_BITS) - 1) +// mask of VFS id (e.g. 0x00007000) +#define VFS_INDEX_MASK (VFS_MAX_COUNT << CONFIG_MAX_FD_BITS) +#define VFS_INDEX_S CONFIG_MAX_FD_BITS + +typedef struct vfs_entry_ { + esp_vfs_t vfs; // contains pointers to VFS functions + char path_prefix[ESP_VFS_PATH_MAX]; // path prefix mapped to this VFS + size_t path_prefix_len; // micro-optimization to avoid doing extra strlen + void* ctx; // optional pointer which can be passed to VFS + int offset; // index of this structure in s_vfs array +} vfs_entry_t; + +static vfs_entry_t* s_vfs[VFS_MAX_COUNT] = { 0 }; +static size_t s_vfs_count = 0; + +esp_err_t esp_vfs_register(const char* base_path, const esp_vfs_t* vfs, void* ctx) +{ + if (s_vfs_count >= VFS_MAX_COUNT) { + return ESP_ERR_NO_MEM; + } + size_t len = strlen(base_path); + if (len < 2 || len > ESP_VFS_PATH_MAX) { + return ESP_ERR_INVALID_ARG; + } + if (base_path[0] != '/' || base_path[len - 1] == '/') { + return ESP_ERR_INVALID_ARG; + } + vfs_entry_t *entry = (vfs_entry_t*) malloc(sizeof(vfs_entry_t)); + if (entry == NULL) { + return ESP_ERR_NO_MEM; + } + strcpy(entry->path_prefix, base_path); // we have already verified argument length + memcpy(&entry->vfs, vfs, sizeof(esp_vfs_t)); + entry->path_prefix_len = len; + entry->ctx = ctx; + entry->offset = s_vfs_count; + s_vfs[s_vfs_count] = entry; + ++s_vfs_count; + return ESP_OK; +} + +static const vfs_entry_t* get_vfs_for_fd(int fd) +{ + int index = ((fd & VFS_INDEX_MASK) >> VFS_INDEX_S); + if (index >= s_vfs_count) { + return NULL; + } + return s_vfs[index]; +} + +static int translate_fd(const vfs_entry_t* vfs, int fd) +{ + return (fd & VFS_FD_MASK) + vfs->vfs.fd_offset; +} + +static const char* translate_path(const vfs_entry_t* vfs, const char* src_path) +{ + assert(strncmp(src_path, vfs->path_prefix, vfs->path_prefix_len) == 0); + return src_path + vfs->path_prefix_len; +} + +static const vfs_entry_t* get_vfs_for_path(const char* path) +{ + size_t len = strlen(path); + for (size_t i = 0; i < s_vfs_count; ++i) { + const vfs_entry_t* vfs = s_vfs[i]; + if (len < vfs->path_prefix_len + 1) { // +1 is for the trailing slash after base path + continue; + } + if (memcmp(path, vfs->path_prefix, vfs->path_prefix_len) != 0) { // match prefix + continue; + } + if (path[vfs->path_prefix_len] != '/') { // don't match "/data" prefix for "/data1/foo.txt" + continue; + } + return vfs; + } + return NULL; +} + +/* + * Using huge multi-line macros is never nice, but in this case + * the only alternative is to repeat this chunk of code (with different function names) + * for each syscall being implemented. Given that this define is contained within a single + * file, this looks like a good tradeoff. + * + * First we check if syscall is implemented by VFS (corresponding member is not NULL), + * then call the right flavor of the method (e.g. open or open_p) depending on + * ESP_VFS_FLAG_CONTEXT_PTR flag. If ESP_VFS_FLAG_CONTEXT_PTR is set, context is passed + * in as first argument and _p variant is used for the call. + * It is enough to check just one of them for NULL, as both variants are part of a union. + */ +#define CHECK_AND_CALL(ret, r, pvfs, func, ...) \ + if (pvfs->vfs.func == NULL) { \ + __errno_r(r) = ENOSYS; \ + return -1; \ + } \ + if (pvfs->vfs.flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ + ret = (*pvfs->vfs.func ## _p)(pvfs->ctx, __VA_ARGS__); \ + } else { \ + ret = (*pvfs->vfs.func)(__VA_ARGS__);\ + } + + +int esp_vfs_open(struct _reent *r, const char * path, int flags, int mode) +{ + const vfs_entry_t* vfs = get_vfs_for_path(path); + if (vfs == NULL) { + __errno_r(r) = ENOENT; + return -1; + } + const char* path_within_vfs = translate_path(vfs, path); + int ret; + CHECK_AND_CALL(ret, r, vfs, open, path_within_vfs, flags, mode); + if (ret < 0) { + return ret; + } + assert(ret >= vfs->vfs.fd_offset); + return ret - vfs->vfs.fd_offset + (vfs->offset << VFS_INDEX_S); +} + +ssize_t esp_vfs_write(struct _reent *r, int fd, const void * data, size_t size) +{ + const vfs_entry_t* vfs = get_vfs_for_fd(fd); + if (vfs == NULL) { + __errno_r(r) = EBADF; + return -1; + } + int local_fd = translate_fd(vfs, fd); + int ret; + CHECK_AND_CALL(ret, r, vfs, write, local_fd, data, size); + return ret; +} + +off_t esp_vfs_lseek(struct _reent *r, int fd, off_t size, int mode) +{ + const vfs_entry_t* vfs = get_vfs_for_fd(fd); + if (vfs == NULL) { + __errno_r(r) = EBADF; + return -1; + } + int local_fd = translate_fd(vfs, fd); + int ret; + CHECK_AND_CALL(ret, r, vfs, lseek, local_fd, size, mode); + return ret; +} + +ssize_t esp_vfs_read(struct _reent *r, int fd, void * dst, size_t size) +{ + const vfs_entry_t* vfs = get_vfs_for_fd(fd); + if (vfs == NULL) { + __errno_r(r) = EBADF; + return -1; + } + int local_fd = translate_fd(vfs, fd); + int ret; + CHECK_AND_CALL(ret, r, vfs, read, local_fd, dst, size); + return ret; +} + + +int esp_vfs_close(struct _reent *r, int fd) +{ + const vfs_entry_t* vfs = get_vfs_for_fd(fd); + if (vfs == NULL) { + __errno_r(r) = EBADF; + return -1; + } + int local_fd = translate_fd(vfs, fd); + int ret; + CHECK_AND_CALL(ret, r, vfs, close, local_fd); + return ret; +} + +int esp_vfs_fstat(struct _reent *r, int fd, struct stat * st) +{ + const vfs_entry_t* vfs = get_vfs_for_fd(fd); + if (vfs == NULL) { + __errno_r(r) = EBADF; + return -1; + } + int local_fd = translate_fd(vfs, fd); + int ret; + CHECK_AND_CALL(ret, r, vfs, fstat, local_fd, st); + return ret; +} + +int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st) +{ + const vfs_entry_t* vfs = get_vfs_for_path(path); + if (vfs == NULL) { + __errno_r(r) = ENOENT; + return -1; + } + const char* path_within_vfs = translate_path(vfs, path); + int ret; + CHECK_AND_CALL(ret, r, vfs, stat, path_within_vfs, st); + return ret; +} + +int esp_vfs_link(struct _reent *r, const char* n1, const char* n2) +{ + const vfs_entry_t* vfs = get_vfs_for_path(n1); + if (vfs == NULL) { + __errno_r(r) = ENOENT; + return -1; + } + const vfs_entry_t* vfs2 = get_vfs_for_path(n2); + if (vfs != vfs2) { + __errno_r(r) = EXDEV; + return -1; + } + const char* path1_within_vfs = translate_path(vfs, n1); + const char* path2_within_vfs = translate_path(vfs, n2); + int ret; + CHECK_AND_CALL(ret, r, vfs, link, path1_within_vfs, path2_within_vfs); + return ret; +} + +int esp_vfs_unlink(struct _reent *r, const char *path) +{ + const vfs_entry_t* vfs = get_vfs_for_path(path); + if (vfs == NULL) { + __errno_r(r) = ENOENT; + return -1; + } + const char* path_within_vfs = translate_path(vfs, path); + int ret; + CHECK_AND_CALL(ret, r, vfs, unlink, path_within_vfs); + return ret; +} + +int esp_vfs_rename(struct _reent *r, const char *src, const char *dst) +{ + const vfs_entry_t* vfs = get_vfs_for_path(src); + if (vfs == NULL) { + __errno_r(r) = ENOENT; + return -1; + } + const vfs_entry_t* vfs_dst = get_vfs_for_path(dst); + if (vfs != vfs_dst) { + __errno_r(r) = EXDEV; + return -1; + } + const char* src_within_vfs = translate_path(vfs, src); + const char* dst_within_vfs = translate_path(vfs, dst); + int ret; + CHECK_AND_CALL(ret, r, vfs, rename, src_within_vfs, dst_within_vfs); + return ret; +} diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c new file mode 100644 index 0000000000..d9d755f9be --- /dev/null +++ b/components/vfs/vfs_uart.c @@ -0,0 +1,103 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include "esp_vfs.h" +#include "esp_attr.h" +#include "sys/errno.h" +#include "sys/lock.h" +#include "soc/uart_struct.h" +#include "sdkconfig.h" + +static uart_dev_t* s_uarts[3] = {&UART0, &UART1, &UART2}; +static _lock_t s_uart_locks[3]; // per-UART locks, lazily initialized + +static int IRAM_ATTR uart_open(const char * path, int flags, int mode) +{ + // this is fairly primitive, we should check if file is opened read only, + // and error out if write is requested + if (strcmp(path, "/0") == 0) { + return 0; + } else if (strcmp(path, "/1") == 0) { + return 1; + } else if (strcmp(path, "/2") == 0) { + return 2; + } + errno = ENOENT; + return -1; +} + +static void IRAM_ATTR uart_tx_char(uart_dev_t* uart, int c) +{ + while (uart->status.txfifo_cnt >= 127) { + ; + } + uart->fifo.rw_byte = c; +} + + +static size_t IRAM_ATTR uart_write(int fd, const void * data, size_t size) +{ + assert(fd >=0 && fd < 3); + const char *data_c = (const char *)data; + uart_dev_t* uart = s_uarts[fd]; + /* + * Even though newlib does stream locking on each individual stream, we need + * a dedicated UART lock if two streams (stdout and stderr) point to the + * same UART. + */ + _lock_acquire_recursive(&s_uart_locks[fd]); + for (size_t i = 0; i < size; i++) { +#if CONFIG_NEWLIB_STDOUT_ADDCR + if (data_c[i]=='\n') { + uart_tx_char(uart, '\r'); + } +#endif + uart_tx_char(uart, data_c[i]); + } + _lock_release_recursive(&s_uart_locks[fd]); + return size; +} + +static int IRAM_ATTR uart_fstat(int fd, struct stat * st) +{ + assert(fd >=0 && fd < 3); + st->st_mode = S_IFCHR; + return 0; +} + +static int IRAM_ATTR uart_close(int fd) +{ + assert(fd >=0 && fd < 3); + return 0; +} + +void esp_vfs_dev_uart_register() +{ + esp_vfs_t vfs = { + .fd_offset = 0, + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &uart_write, + .open = &uart_open, + .fstat = &uart_fstat, + .close = &uart_close, + .read = NULL, // TODO: implement reading from UART + .lseek = NULL, + .stat = NULL, + .link = NULL, + .unlink = NULL, + .rename = NULL + }; + ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL)); +} diff --git a/components/wpa_supplicant/COPYING b/components/wpa_supplicant/COPYING new file mode 100644 index 0000000000..7efce0dee1 --- /dev/null +++ b/components/wpa_supplicant/COPYING @@ -0,0 +1,22 @@ +wpa_supplicant and hostapd +-------------------------- + +Copyright (c) 2002-2016, Jouni Malinen and contributors +All Rights Reserved. + + +See the README file for the current license terms. + +This software was previously distributed under BSD/GPL v2 dual license +terms that allowed either of those license alternatives to be +selected. As of February 11, 2012, the project has chosen to use only +the BSD license option for future distribution. As such, the GPL v2 +license option is no longer used. It should be noted that the BSD +license option (the one with advertisement clause removed) is compatible +with GPL and as such, does not prevent use of this software in projects +that use GPL. + +Some of the files may still include pointers to GPL version 2 license +terms. However, such copyright and license notifications are maintained +only for attribution purposes and any distribution of this software +after February 11, 2012 is no longer under the GPL v2 option. diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk new file mode 100644 index 0000000000..b01eb83be9 --- /dev/null +++ b/components/wpa_supplicant/component.mk @@ -0,0 +1,4 @@ +COMPONENT_ADD_INCLUDEDIRS := include port/include +COMPONENT_SRCDIRS := src/crypto + +CFLAGS += -DEMBEDDED_SUPP -D__ets__ -Wno-strict-aliasing diff --git a/components/wpa_supplicant/include/crypto/aes.h b/components/wpa_supplicant/include/crypto/aes.h new file mode 100644 index 0000000000..ba384a9dae --- /dev/null +++ b/components/wpa_supplicant/include/crypto/aes.h @@ -0,0 +1,27 @@ +/* + * AES functions + * Copyright (c) 2003-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef AES_H +#define AES_H + +#define AES_BLOCK_SIZE 16 + +void * aes_encrypt_init(const u8 *key, size_t len); +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); +void aes_encrypt_deinit(void *ctx); +void * aes_decrypt_init(const u8 *key, size_t len); +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); +void aes_decrypt_deinit(void *ctx); + +#endif /* AES_H */ diff --git a/components/wpa_supplicant/include/crypto/aes_i.h b/components/wpa_supplicant/include/crypto/aes_i.h new file mode 100644 index 0000000000..1063422a81 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/aes_i.h @@ -0,0 +1,131 @@ +/* + * AES (Rijndael) cipher + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef AES_I_H +#define AES_I_H + +#include "aes.h" + +/* #define FULL_UNROLL */ +#define AES_SMALL_TABLES + +extern const u32 Te0[256]; +extern const u32 Te1[256]; +extern const u32 Te2[256]; +extern const u32 Te3[256]; +extern const u32 Te4[256]; +extern const u32 Td0[256]; +extern const u32 Td1[256]; +extern const u32 Td2[256]; +extern const u32 Td3[256]; +extern const u32 Td4[256]; +extern const u32 rcon[10]; +extern const u8 Td4s[256]; +extern const u8 rcons[10]; + +#ifndef AES_SMALL_TABLES + +#define RCON(i) rcon[(i)] + +#define TE0(i) Te0[((i) >> 24) & 0xff] +#define TE1(i) Te1[((i) >> 16) & 0xff] +#define TE2(i) Te2[((i) >> 8) & 0xff] +#define TE3(i) Te3[(i) & 0xff] +#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) +#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff) +#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000) +#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000) +#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00) +#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff) +#define TE411(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) +#define TE422(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE433(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE444(i) (Te4[(i) & 0xff] & 0x000000ff) +#define TE4(i) (Te4[(i)] & 0x000000ff) + +#define TD0(i) Td0[((i) >> 24) & 0xff] +#define TD1(i) Td1[((i) >> 16) & 0xff] +#define TD2(i) Td2[((i) >> 8) & 0xff] +#define TD3(i) Td3[(i) & 0xff] +#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000) +#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000) +#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00) +#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff) +#define TD0_(i) Td0[(i) & 0xff] +#define TD1_(i) Td1[(i) & 0xff] +#define TD2_(i) Td2[(i) & 0xff] +#define TD3_(i) Td3[(i) & 0xff] + +#else /* AES_SMALL_TABLES */ + +#define RCON(i) (rcons[(i)] << 24) + +static inline u32 rotr(u32 val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + +#define TE0(i) Te0[((i) >> 24) & 0xff] +#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) +#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) +#define TE3(i) rotr(Te0[(i) & 0xff], 24) +#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) +#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) +#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) +#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) +#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) +#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) +#define TE411(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) +#define TE422(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE433(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE444(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) +#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) + +#define TD0(i) Td0[((i) >> 24) & 0xff] +#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) +#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) +#define TD3(i) rotr(Td0[(i) & 0xff], 24) +#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) +#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) +#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) +#define TD44(i) (Td4s[(i) & 0xff]) +#define TD0_(i) Td0[(i) & 0xff] +#define TD1_(i) rotr(Td0[(i) & 0xff], 8) +#define TD2_(i) rotr(Td0[(i) & 0xff], 16) +#define TD3_(i) rotr(Td0[(i) & 0xff], 24) + +#endif /* AES_SMALL_TABLES */ + +#ifdef _MSC_VER +#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) +#define GETU32(p) SWAP(*((u32 *)(p))) +#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } +#else +#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ +((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +#define PUTU32(ct, st) { \ +(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ +(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } +#endif + +#define AES_PRIV_SIZE (4 * 4 * 15 + 4) +#define AES_PRIV_NR_POS (4 * 15) + +int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits); + +#endif /* AES_I_H */ diff --git a/components/wpa_supplicant/include/crypto/aes_wrap.h b/components/wpa_supplicant/include/crypto/aes_wrap.h new file mode 100644 index 0000000000..4b1c7b083b --- /dev/null +++ b/components/wpa_supplicant/include/crypto/aes_wrap.h @@ -0,0 +1,48 @@ +/* + * AES-based functions + * + * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * - One-Key CBC MAC (OMAC1) hash with AES-128 + * - AES-128 CTR mode encryption + * - AES-128 EAX mode encryption/decryption + * - AES-128 CBC + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef AES_WRAP_H +#define AES_WRAP_H + +int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); +int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); +int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem, + const u8 *addr[], const size_t *len, + u8 *mac); +int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, + u8 *mac); +int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out); +int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, + u8 *data, size_t data_len); +int __must_check aes_128_eax_encrypt(const u8 *key, + const u8 *nonce, size_t nonce_len, + const u8 *hdr, size_t hdr_len, + u8 *data, size_t data_len, u8 *tag); +int __must_check aes_128_eax_decrypt(const u8 *key, + const u8 *nonce, size_t nonce_len, + const u8 *hdr, size_t hdr_len, + u8 *data, size_t data_len, const u8 *tag); +int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, + size_t data_len); +int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, + size_t data_len); + +#endif /* AES_WRAP_H */ diff --git a/components/wpa_supplicant/include/crypto/base64.h b/components/wpa_supplicant/include/crypto/base64.h new file mode 100644 index 0000000000..b87a1682f8 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/base64.h @@ -0,0 +1,23 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef BASE64_H +#define BASE64_H + +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len); +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len); + +#endif /* BASE64_H */ diff --git a/components/wpa_supplicant/include/crypto/common.h b/components/wpa_supplicant/include/crypto/common.h new file mode 100644 index 0000000000..319b861e45 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/common.h @@ -0,0 +1,481 @@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "os.h" + +#if defined(__XTENSA__) +#include +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#endif /*__XTENSA__*/ + +#if defined(__linux__) || defined(__GLIBC__) +#include +#include +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__OpenBSD__) +#include +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +#ifdef __OpenBSD__ +#define bswap_16 swap16 +#define bswap_32 swap32 +#define bswap_64 swap64 +#else /* __OpenBSD__ */ +#define bswap_16 bswap16 +#define bswap_32 bswap32 +#define bswap_64 bswap64 +#endif /* __OpenBSD__ */ +#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || + * defined(__DragonFly__) || defined(__OpenBSD__) */ + +#ifdef __APPLE__ +#include +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +static inline unsigned short bswap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int bswap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} +#endif /* __APPLE__ */ + +#ifdef CONFIG_TI_COMPILER +#define __BIG_ENDIAN 4321 +#define __LITTLE_ENDIAN 1234 +#ifdef __big_endian__ +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif +#endif /* CONFIG_TI_COMPILER */ + +#ifdef __SYMBIAN32__ +#define __BIG_ENDIAN 4321 +#define __LITTLE_ENDIAN 1234 +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif /* __SYMBIAN32__ */ + +#ifdef CONFIG_NATIVE_WINDOWS +#include + +typedef int socklen_t; + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 /* not supported */ +#endif + +#endif /* CONFIG_NATIVE_WINDOWS */ + +#ifdef _MSC_VER +#define inline __inline + +#undef vsnprintf +#define vsnprintf _vsnprintf +#undef close +#define close closesocket +#endif /* _MSC_VER */ + + +/* Define platform specific integer types */ + +#ifdef _MSC_VER +typedef UINT64 u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef INT64 s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* _MSC_VER */ + +#ifdef __vxworks +typedef unsigned long long u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef long long s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* __vxworks */ + +#ifdef CONFIG_TI_COMPILER +#ifdef _LLONG_AVAILABLE +typedef unsigned long long u64; +#else +/* + * TODO: 64-bit variable not available. Using long as a workaround to test the + * build, but this will likely not work for all operations. + */ +typedef unsigned long u64; +#endif +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; +#define WPA_TYPES_DEFINED +#endif /* CONFIG_TI_COMPILER */ + +#ifdef __SYMBIAN32__ +#define __REMOVE_PLATSEC_DIAGNOSTICS__ +#include +typedef TUint64 u64; +typedef TUint32 u32; +typedef TUint16 u16; +typedef TUint8 u8; +#define WPA_TYPES_DEFINED +#endif /* __SYMBIAN32__ */ + +#ifndef WPA_TYPES_DEFINED +#ifdef CONFIG_USE_INTTYPES_H +#include +#else +#include +#endif + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; +#define WPA_TYPES_DEFINED +#endif /* !WPA_TYPES_DEFINED */ + + +/* Define platform specific byte swapping macros */ + +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) + +static inline unsigned short wpa_swap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int wpa_swap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} + +#define le_to_host16(n) (n) +#define host_to_le16(n) (n) +#define be_to_host16(n) wpa_swap_16(n) +#define host_to_be16(n) wpa_swap_16(n) +#define le_to_host32(n) (n) +#define be_to_host32(n) wpa_swap_32(n) +#define host_to_be32(n) wpa_swap_32(n) + +#define WPA_BYTE_SWAP_DEFINED + +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ + + +#ifndef WPA_BYTE_SWAP_DEFINED + +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#if defined(sparc) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* __BIG_ENDIAN */ +#endif /* __LITTLE_ENDIAN */ +#endif /* __BYTE_ORDER */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le_to_host16(n) ((__force u16) (le16) (n)) +#define host_to_le16(n) ((__force le16) (u16) (n)) +#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) +#define host_to_be16(n) ((__force be16) bswap_16((n))) +#define le_to_host32(n) ((__force u32) (le32) (n)) +#define host_to_le32(n) ((__force le32) (u32) (n)) +#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) +#define host_to_be32(n) ((__force be32) bswap_32((n))) +#define le_to_host64(n) ((__force u64) (le64) (n)) +#define host_to_le64(n) ((__force le64) (u64) (n)) +#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) +#define host_to_be64(n) ((__force be64) bswap_64((n))) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define le_to_host16(n) bswap_16(n) +#define host_to_le16(n) bswap_16(n) +#define be_to_host16(n) (n) +#define host_to_be16(n) (n) +#define le_to_host32(n) bswap_32(n) +#define be_to_host32(n) (n) +#define host_to_be32(n) (n) +#define le_to_host64(n) bswap_64(n) +#define host_to_le64(n) bswap_64(n) +#define be_to_host64(n) (n) +#define host_to_be64(n) (n) +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#else +#error Could not determine CPU byte order +#endif + +#define WPA_BYTE_SWAP_DEFINED +#endif /* !WPA_BYTE_SWAP_DEFINED */ + + +/* Macros for handling unaligned memory accesses */ + +#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) +#define WPA_PUT_BE16(a, val) \ + do { \ + (a)[0] = ((u16) (val)) >> 8; \ + (a)[1] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define WPA_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ + ((u32) (a)[2])) +#define WPA_PUT_BE24(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[2] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ + (((u32) (a)[2]) << 8) | ((u32) (a)[3])) +#define WPA_PUT_BE32(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[3] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ + (((u32) (a)[1]) << 8) | ((u32) (a)[0])) +#define WPA_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ + (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ + (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ + (((u64) (a)[6]) << 8) | ((u64) (a)[7])) +#define WPA_PUT_BE64(a, val) \ + do { \ + (a)[0] = (u8) (((u64) (val)) >> 56); \ + (a)[1] = (u8) (((u64) (val)) >> 48); \ + (a)[2] = (u8) (((u64) (val)) >> 40); \ + (a)[3] = (u8) (((u64) (val)) >> 32); \ + (a)[4] = (u8) (((u64) (val)) >> 24); \ + (a)[5] = (u8) (((u64) (val)) >> 16); \ + (a)[6] = (u8) (((u64) (val)) >> 8); \ + (a)[7] = (u8) (((u64) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ + (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ + (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ + (((u64) (a)[1]) << 8) | ((u64) (a)[0])) + + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif +#ifndef ETH_P_ALL +#define ETH_P_ALL 0x0003 +#endif +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ +#ifndef ETH_P_EAPOL +#define ETH_P_EAPOL ETH_P_PAE +#endif /* ETH_P_EAPOL */ +#ifndef ETH_P_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif /* ETH_P_RSN_PREAUTH */ +#ifndef ETH_P_RRB +#define ETH_P_RRB 0x890D +#endif /* ETH_P_RRB */ + + +#ifdef __GNUC__ +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) +#define STRUCT_PACKED __attribute__ ((packed)) +#else +#define PRINTF_FORMAT(a,b) +#define STRUCT_PACKED +#endif + +#ifdef CONFIG_ANSI_C_EXTRA + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement + * due to possible buffer overflow; see, e.g., + * http://www.ijs.si/software/snprintf/ for portable implementation of + * snprintf. */ +int snprintf(char *str, size_t size, const char *format, ...); + +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ + +/* getopt - only used in main.c */ +int getopt(int argc, char *const argv[], const char *optstring); +extern char *optarg; +extern int optind; + +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF +#ifndef __socklen_t_defined +typedef int socklen_t; +#endif +#endif + +/* inline - define as __inline or just define it to be empty, if needed */ +#ifdef CONFIG_NO_INLINE +#define inline +#else +#define inline __inline +#endif + +#ifndef __func__ +#define __func__ "__func__ not defined" +#endif + +#ifndef bswap_16 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) +#endif + +#ifndef bswap_32 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ + (((u32) (a) << 8) & 0xff0000) | \ + (((u32) (a) >> 8) & 0xff00) | \ + (((u32) (a) >> 24) & 0xff)) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +#ifdef _WIN32_WCE +void perror(const char *s); +#endif /* _WIN32_WCE */ + +#endif /* CONFIG_ANSI_C_EXTRA */ + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#endif + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +/* + * Definitions for sparse validation + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) + */ +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef u16 __bitwise be16; +typedef u16 __bitwise le16; +typedef u32 __bitwise be32; +typedef u32 __bitwise le32; +typedef u64 __bitwise be64; +typedef u64 __bitwise le64; + +#ifndef __must_check +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __must_check __attribute__((__warn_unused_result__)) +#else +#define __must_check +#endif /* __GNUC__ */ +#endif /* __must_check */ + +int hwaddr_aton(const char *txt, u8 *addr); +int hwaddr_aton2(const char *txt, u8 *addr); +int hexstr2bin(const char *hex, u8 *buf, size_t len); +void inc_byte_array(u8 *counter, size_t len); +void wpa_get_ntp_timestamp(u8 *buf); +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + +#ifdef CONFIG_NATIVE_WINDOWS +void wpa_unicode2ascii_inplace(TCHAR *str); +TCHAR * wpa_strdup_tchar(const char *str); +#else /* CONFIG_NATIVE_WINDOWS */ +#define wpa_unicode2ascii_inplace(s) do { } while (0) +#define wpa_strdup_tchar(s) strdup((s)) +#endif /* CONFIG_NATIVE_WINDOWS */ + +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); + +static inline int is_zero_ether_addr(const u8 *a) +{ + return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); +} + +/* + * gcc 4.4 ends up generating strict-aliasing warnings about some very common + * networking socket uses that do not really result in a real problem and + * cannot be easily avoided with union-based type-punning due to struct + * definitions including another struct in system header files. To avoid having + * to fully disable strict-aliasing warnings, provide a mechanism to hide the + * typecast from aliasing for now. A cleaner solution will hopefully be found + * in the future to handle these cases. + */ +void * __hide_aliasing_typecast(void *foo); +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) + +#endif /* COMMON_H */ diff --git a/components/wpa_supplicant/include/crypto/crypto.h b/components/wpa_supplicant/include/crypto/crypto.h new file mode 100644 index 0000000000..f0b9f22430 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/crypto.h @@ -0,0 +1,471 @@ +/* + * WPA Supplicant / wrapper functions for crypto libraries + * Copyright (c) 2004-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This file defines the cryptographic functions that need to be implemented + * for wpa_supplicant and hostapd. When TLS is not used, internal + * implementation of MD5, SHA1, and AES is used and no external libraries are + * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the + * crypto library used by the TLS implementation is expected to be used for + * non-TLS needs, too, in order to save space by not implementing these + * functions twice. + * + * Wrapper code for using each crypto library is in its own file (crypto*.c) + * and one of these files is build and linked in to provide the functions + * defined here. + */ + +#ifndef CRYPTO_H +#define CRYPTO_H + +/** + * md4_vector - MD4 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); + +/** + * md5_vector - MD5 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); + +#ifdef CONFIG_FIPS +/** + * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed) + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac); +#else /* CONFIG_FIPS */ +#define md5_vector_non_fips_allow md5_vector +#endif /* CONFIG_FIPS */ + + +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); + +/** + * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF + * @seed: Seed/key for the PRF + * @seed_len: Seed length in bytes + * @x: Buffer for PRF output + * @xlen: Output length in bytes + * Returns: 0 on success, -1 on failure + * + * This function implements random number generation specified in NIST FIPS + * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to + * SHA-1, but has different message padding. + */ +int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, + size_t xlen); + +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); + +/** + * des_encrypt - Encrypt one block with DES + * @clear: 8 octets (in) + * @key: 7 octets (in) (no parity bits included) + * @cypher: 8 octets (out) + */ +void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher); + +/** + * aes_encrypt_init - Initialize AES for encryption + * @key: Encryption key + * @len: Key length in bytes (usually 16, i.e., 128 bits) + * Returns: Pointer to context data or %NULL on failure + */ +void * aes_encrypt_init(const u8 *key, size_t len); + +/** + * aes_encrypt - Encrypt one AES block + * @ctx: Context pointer from aes_encrypt_init() + * @plain: Plaintext data to be encrypted (16 bytes) + * @crypt: Buffer for the encrypted data (16 bytes) + */ +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); + +/** + * aes_encrypt_deinit - Deinitialize AES encryption + * @ctx: Context pointer from aes_encrypt_init() + */ +void aes_encrypt_deinit(void *ctx); + +/** + * aes_decrypt_init - Initialize AES for decryption + * @key: Decryption key + * @len: Key length in bytes (usually 16, i.e., 128 bits) + * Returns: Pointer to context data or %NULL on failure + */ +void * aes_decrypt_init(const u8 *key, size_t len); + +/** + * aes_decrypt - Decrypt one AES block + * @ctx: Context pointer from aes_encrypt_init() + * @crypt: Encrypted data (16 bytes) + * @plain: Buffer for the decrypted data (16 bytes) + */ +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); + +/** + * aes_decrypt_deinit - Deinitialize AES decryption + * @ctx: Context pointer from aes_encrypt_init() + */ +void aes_decrypt_deinit(void *ctx); + + +enum crypto_hash_alg { + CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1, + CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1, + CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256 +}; + + +struct crypto_hash; + +/** + * crypto_hash_init - Initialize hash/HMAC function + * @alg: Hash algorithm + * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed + * @key_len: Length of the key in bytes + * Returns: Pointer to hash context to use with other hash functions or %NULL + * on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, + size_t key_len); + +/** + * crypto_hash_update - Add data to hash calculation + * @ctx: Context pointer from crypto_hash_init() + * @data: Data buffer to add + * @len: Length of the buffer + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len); + +/** + * crypto_hash_finish - Complete hash calculation + * @ctx: Context pointer from crypto_hash_init() + * @hash: Buffer for hash value or %NULL if caller is just freeing the hash + * context + * @len: Pointer to length of the buffer or %NULL if caller is just freeing the + * hash context; on return, this is set to the actual length of the hash value + * Returns: 0 on success, -1 if buffer is too small (len set to needed length), + * or -2 on other failures (including failed crypto_hash_update() operations) + * + * This function calculates the hash value and frees the context buffer that + * was used for hash calculation. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len); + + +enum crypto_cipher_alg { + CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES, + CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4 +}; + +struct crypto_cipher; + +/** + * crypto_cipher_init - Initialize block/stream cipher function + * @alg: Cipher algorithm + * @iv: Initialization vector for block ciphers or %NULL for stream ciphers + * @key: Cipher key + * @key_len: Length of key in bytes + * Returns: Pointer to cipher context to use with other cipher functions or + * %NULL on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len); + +/** + * crypto_cipher_encrypt - Cipher encrypt + * @ctx: Context pointer from crypto_cipher_init() + * @plain: Plaintext to cipher + * @crypt: Resulting ciphertext + * @len: Length of the plaintext + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx, + const u8 *plain, u8 *crypt, size_t len); + +/** + * crypto_cipher_decrypt - Cipher decrypt + * @ctx: Context pointer from crypto_cipher_init() + * @crypt: Ciphertext to decrypt + * @plain: Resulting plaintext + * @len: Length of the cipher text + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx, + const u8 *crypt, u8 *plain, size_t len); + +/** + * crypto_cipher_decrypt - Free cipher context + * @ctx: Context pointer from crypto_cipher_init() + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_cipher_deinit(struct crypto_cipher *ctx); + + +struct crypto_public_key; +struct crypto_private_key; + +/** + * crypto_public_key_import - Import an RSA public key + * @key: Key buffer (DER encoded RSA public key) + * @len: Key buffer length in bytes + * Returns: Pointer to the public key or %NULL on failure + * + * This function can just return %NULL if the crypto library supports X.509 + * parsing. In that case, crypto_public_key_from_cert() is used to import the + * public key from a certificate. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len); + +/** + * crypto_private_key_import - Import an RSA private key + * @key: Key buffer (DER encoded RSA private key) + * @len: Key buffer length in bytes + * @passwd: Key encryption password or %NULL if key is not encrypted + * Returns: Pointer to the private key or %NULL on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_private_key * crypto_private_key_import(const u8 *key, + size_t len, + const char *passwd); + +/** + * crypto_public_key_from_cert - Import an RSA public key from a certificate + * @buf: DER encoded X.509 certificate + * @len: Certificate buffer length in bytes + * Returns: Pointer to public key or %NULL on failure + * + * This function can just return %NULL if the crypto library does not support + * X.509 parsing. In that case, internal code will be used to parse the + * certificate and public key is imported using crypto_public_key_import(). + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, + size_t len); + +/** + * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5) + * @key: Public key + * @in: Plaintext buffer + * @inlen: Length of plaintext buffer in bytes + * @out: Output buffer for encrypted data + * @outlen: Length of output buffer in bytes; set to used length on success + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_public_key_encrypt_pkcs1_v15( + struct crypto_public_key *key, const u8 *in, size_t inlen, + u8 *out, size_t *outlen); + +/** + * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5) + * @key: Private key + * @in: Encrypted buffer + * @inlen: Length of encrypted buffer in bytes + * @out: Output buffer for encrypted data + * @outlen: Length of output buffer in bytes; set to used length on success + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_private_key_decrypt_pkcs1_v15( + struct crypto_private_key *key, const u8 *in, size_t inlen, + u8 *out, size_t *outlen); + +/** + * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1) + * @key: Private key from crypto_private_key_import() + * @in: Plaintext buffer + * @inlen: Length of plaintext buffer in bytes + * @out: Output buffer for encrypted (signed) data + * @outlen: Length of output buffer in bytes; set to used length on success + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen); + +/** + * crypto_public_key_free - Free public key + * @key: Public key + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_public_key_free(struct crypto_public_key *key); + +/** + * crypto_private_key_free - Free private key + * @key: Private key from crypto_private_key_import() + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_private_key_free(struct crypto_private_key *key); + +/** + * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature + * @key: Public key + * @crypt: Encrypted signature data (using the private key) + * @crypt_len: Encrypted signature data length + * @plain: Buffer for plaintext (at least crypt_len bytes) + * @plain_len: Plaintext length (max buffer size on input, real len on output); + * Returns: 0 on success, -1 on failure + */ +int __must_check crypto_public_key_decrypt_pkcs1( + struct crypto_public_key *key, const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len); + +/** + * crypto_global_init - Initialize crypto wrapper + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_global_init(void); + +/** + * crypto_global_deinit - Deinitialize crypto wrapper + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_global_deinit(void); + +/** + * crypto_mod_exp - Modular exponentiation of large integers + * @base: Base integer (big endian byte array) + * @base_len: Length of base integer in bytes + * @power: Power integer (big endian byte array) + * @power_len: Length of power integer in bytes + * @modulus: Modulus integer (big endian byte array) + * @modulus_len: Length of modulus integer in bytes + * @result: Buffer for the result + * @result_len: Result length (max buffer size on input, real len on output) + * Returns: 0 on success, -1 on failure + * + * This function calculates result = base ^ power mod modulus. modules_len is + * used as the maximum size of modulus buffer. It is set to the used size on + * success. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len); + +/** + * rc4_skip - XOR RC4 stream to given data with skip-stream-start + * @key: RC4 key + * @keylen: RC4 key length + * @skip: number of bytes to skip from the beginning of the RC4 stream + * @data: data to be XOR'ed with RC4 stream + * @data_len: buf length + * Returns: 0 on success, -1 on failure + * + * Generate RC4 pseudo random stream for the given key, skip beginning of the + * stream, and XOR the end result with the data buffer to perform RC4 + * encryption/decryption. + */ +int rc4_skip(const u8 *key, size_t keylen, size_t skip, + u8 *data, size_t data_len); + +#endif /* CRYPTO_H */ diff --git a/components/wpa_supplicant/include/crypto/dh_group5.h b/components/wpa_supplicant/include/crypto/dh_group5.h new file mode 100644 index 0000000000..595f1114fe --- /dev/null +++ b/components/wpa_supplicant/include/crypto/dh_group5.h @@ -0,0 +1,23 @@ +/* + * Diffie-Hellman group 5 operations + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef DH_GROUP5_H +#define DH_GROUP5_H + +void * dh5_init(struct wpabuf **priv, struct wpabuf **publ); +struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, + const struct wpabuf *own_private); +void dh5_free(void *ctx); + +#endif /* DH_GROUP5_H */ diff --git a/components/wpa_supplicant/include/crypto/dh_groups.h b/components/wpa_supplicant/include/crypto/dh_groups.h new file mode 100644 index 0000000000..5c61539b70 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/dh_groups.h @@ -0,0 +1,32 @@ +/* + * Diffie-Hellman groups + * Copyright (c) 2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef DH_GROUPS_H +#define DH_GROUPS_H + +struct dh_group { + int id; + const u8 *generator; + size_t generator_len; + const u8 *prime; + size_t prime_len; +}; + +const struct dh_group * dh_groups_get(int id); +struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv); +struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public, + const struct wpabuf *own_private, + const struct dh_group *dh); + +#endif /* DH_GROUPS_H */ diff --git a/components/wpa_supplicant/include/crypto/includes.h b/components/wpa_supplicant/include/crypto/includes.h new file mode 100644 index 0000000000..dbc65759b0 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/includes.h @@ -0,0 +1,65 @@ +/* + * wpa_supplicant/hostapd - Default include files + * Copyright (c) 2005-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This header file is included into all C files so that commonly used header + * files can be selected with OS specific ifdef blocks in one place instead of + * having to have OS/C library specific selection in many files. + */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +/* Include possible build time configuration before including anything else */ +//#include "build_config.h" //don't need anymore +#ifndef __ets__ +#include +#include +#include +#include +#ifndef _WIN32_WCE +#ifndef CONFIG_TI_COMPILER +#include +#include +#endif /* CONFIG_TI_COMPILER */ +#include +#endif /* _WIN32_WCE */ +#include +#include + +#ifndef CONFIG_TI_COMPILER +#ifndef _MSC_VER +#include +#endif /* _MSC_VER */ +#endif /* CONFIG_TI_COMPILER */ + +#ifndef CONFIG_NATIVE_WINDOWS +#ifndef CONFIG_TI_COMPILER +//#include +//#include +//#include +#ifndef __vxworks +#ifndef __SYMBIAN32__ +//#include +#endif /* __SYMBIAN32__ */ +#include +#endif /* __vxworks */ +#endif /* CONFIG_TI_COMPILER */ +#endif /* CONFIG_NATIVE_WINDOWS */ + +#else + +#include "rom/ets_sys.h" + +#endif /* !__ets__ */ + +#endif /* INCLUDES_H */ diff --git a/components/wpa_supplicant/include/crypto/md5.h b/components/wpa_supplicant/include/crypto/md5.h new file mode 100644 index 0000000000..8952590782 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/md5.h @@ -0,0 +1,35 @@ +/* + * MD5 hash implementation and interface functions + * Copyright (c) 2003-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef MD5_H +#define MD5_H + +#define MD5_MAC_LEN 16 + +int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac); +int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac); +#ifdef CONFIG_FIPS +int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len, + size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac); +int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac); +#else /* CONFIG_FIPS */ +#define hmac_md5_vector_non_fips_allow hmac_md5_vector +#define hmac_md5_non_fips_allow hmac_md5 +#endif /* CONFIG_FIPS */ + +#endif /* MD5_H */ diff --git a/components/wpa_supplicant/include/crypto/md5_i.h b/components/wpa_supplicant/include/crypto/md5_i.h new file mode 100644 index 0000000000..b7f6596052 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/md5_i.h @@ -0,0 +1,29 @@ +/* + * MD5 internal definitions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef MD5_I_H +#define MD5_I_H + +struct MD5Context { + u32 buf[4]; + u32 bits[2]; + u8 in[64]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); + +#endif /* MD5_I_H */ diff --git a/components/wpa_supplicant/include/crypto/random.h b/components/wpa_supplicant/include/crypto/random.h new file mode 100644 index 0000000000..cbfa8773fd --- /dev/null +++ b/components/wpa_supplicant/include/crypto/random.h @@ -0,0 +1,34 @@ +/* + * Random number generator + * Copyright (c) 2010-2011, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef RANDOM_H +#define RANDOM_H + +#define CONFIG_NO_RANDOM_POOL + +#ifdef CONFIG_NO_RANDOM_POOL +#define random_init(e) do { } while (0) +#define random_deinit() do { } while (0) +#define random_add_randomness(b, l) do { } while (0) +#define random_get_bytes(b, l) os_get_random((b), (l)) +#define random_pool_ready() 1 +#define random_mark_pool_ready() do { } while (0) +#else /* CONFIG_NO_RANDOM_POOL */ +void random_init(const char *entropy_file); +void random_deinit(void); +void random_add_randomness(const void *buf, size_t len); +int random_get_bytes(void *buf, size_t len); +#endif /* CONFIG_NO_RANDOM_POOL */ + +#endif /* RANDOM_H */ diff --git a/components/wpa_supplicant/include/crypto/sha1.h b/components/wpa_supplicant/include/crypto/sha1.h new file mode 100644 index 0000000000..b3d186bdbc --- /dev/null +++ b/components/wpa_supplicant/include/crypto/sha1.h @@ -0,0 +1,33 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA1_H +#define SHA1_H + +#define SHA1_MAC_LEN 20 + +int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac); +int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac); +int sha1_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len); +int sha1_t_prf(const u8 *key, size_t key_len, const char *label, + const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len); +//int __must_check tls_prf(const u8 *secret, size_t secret_len, +// const char *label, const u8 *seed, size_t seed_len, +// u8 *out, size_t outlen); +int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen); +#endif /* SHA1_H */ diff --git a/components/wpa_supplicant/include/crypto/sha1_i.h b/components/wpa_supplicant/include/crypto/sha1_i.h new file mode 100644 index 0000000000..ec2f82f75b --- /dev/null +++ b/components/wpa_supplicant/include/crypto/sha1_i.h @@ -0,0 +1,29 @@ +/* + * SHA1 internal definitions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA1_I_H +#define SHA1_I_H + +struct SHA1Context { + u32 state[5]; + u32 count[2]; + unsigned char buffer[64]; +}; + +void SHA1Init(struct SHA1Context *context); +void SHA1Update(struct SHA1Context *context, const void *data, u32 len); +void SHA1Final(unsigned char digest[20], struct SHA1Context *context); +void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + +#endif /* SHA1_I_H */ diff --git a/components/wpa_supplicant/include/crypto/sha256.h b/components/wpa_supplicant/include/crypto/sha256.h new file mode 100644 index 0000000000..dc597f09b5 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/sha256.h @@ -0,0 +1,27 @@ +/* + * SHA256 hash implementation and interface functions + * Copyright (c) 2003-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA256_H +#define SHA256_H + +#define SHA256_MAC_LEN 32 + +void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac); +void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac); +void sha256_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len); + +#endif /* SHA256_H */ diff --git a/components/wpa_supplicant/include/wpa/ap_config.h b/components/wpa_supplicant/include/wpa/ap_config.h new file mode 100644 index 0000000000..761becb484 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/ap_config.h @@ -0,0 +1,544 @@ +/* + * hostapd / Configuration definitions and helpers functions + * Copyright (c) 2003-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef HOSTAPD_CONFIG_H +#define HOSTAPD_CONFIG_H + +#include "wpa/defs.h" +//#include "ip_addr.h" +#include "wpa/wpa_common.h" +//#include "common/ieee802_11_common.h" +//#include "wps/wps.h" + +#define MAX_STA_COUNT 4 +#define MAX_VLAN_ID 4094 + +typedef u8 macaddr[ETH_ALEN]; + +struct mac_acl_entry { + macaddr addr; + int vlan_id; +}; + +struct hostapd_radius_servers; +struct ft_remote_r0kh; +struct ft_remote_r1kh; + +#define HOSTAPD_MAX_SSID_LEN 32 + +#define NUM_WEP_KEYS 4 +struct hostapd_wep_keys { + u8 idx; + u8 *key[NUM_WEP_KEYS]; + size_t len[NUM_WEP_KEYS]; + int keys_set; + size_t default_len; /* key length used for dynamic key generation */ +}; + +typedef enum hostap_security_policy { + SECURITY_PLAINTEXT = 0, + SECURITY_STATIC_WEP = 1, + SECURITY_IEEE_802_1X = 2, + SECURITY_WPA_PSK = 3, + SECURITY_WPA = 4 +} secpolicy; + +struct hostapd_ssid { + u8 ssid[HOSTAPD_MAX_SSID_LEN]; + size_t ssid_len; + unsigned int ssid_set:1; + unsigned int utf8_ssid:1; + +// char vlan[IFNAMSIZ + 1]; +// secpolicy security_policy; + + struct hostapd_wpa_psk *wpa_psk; + char *wpa_passphrase; +// char *wpa_psk_file; + + struct hostapd_wep_keys wep; + +#if 0 +#define DYNAMIC_VLAN_DISABLED 0 +#define DYNAMIC_VLAN_OPTIONAL 1 +#define DYNAMIC_VLAN_REQUIRED 2 + int dynamic_vlan; +#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0 +#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1 +#define DYNAMIC_VLAN_NAMING_END 2 + int vlan_naming; +#ifdef CONFIG_FULL_DYNAMIC_VLAN + char *vlan_tagged_interface; +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ + struct hostapd_wep_keys **dyn_vlan_keys; + size_t max_dyn_vlan_keys; +#endif +}; + +#if 0 +#define VLAN_ID_WILDCARD -1 + +struct hostapd_vlan { + struct hostapd_vlan *next; + int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */ + char ifname[IFNAMSIZ + 1]; + int dynamic_vlan; +#ifdef CONFIG_FULL_DYNAMIC_VLAN + +#define DVLAN_CLEAN_BR 0x1 +#define DVLAN_CLEAN_VLAN 0x2 +#define DVLAN_CLEAN_VLAN_PORT 0x4 +#define DVLAN_CLEAN_WLAN_PORT 0x8 + int clean; +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ +}; +#endif + +#define PMK_LEN 32 +struct hostapd_sta_wpa_psk_short { + struct hostapd_sta_wpa_psk_short *next; + u8 psk[PMK_LEN]; +}; + +struct hostapd_wpa_psk { + struct hostapd_wpa_psk *next; + int group; + u8 psk[PMK_LEN]; + u8 addr[ETH_ALEN]; +}; + +#if 0 +struct hostapd_eap_user { + struct hostapd_eap_user *next; + u8 *identity; + size_t identity_len; + struct { + int vendor; + u32 method; + } methods[EAP_MAX_METHODS]; + u8 *password; + size_t password_len; + int phase2; + int force_version; + unsigned int wildcard_prefix:1; + unsigned int password_hash:1; /* whether password is hashed with + * nt_password_hash() */ + int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */ +}; + +struct hostapd_radius_attr { + u8 type; + struct wpabuf *val; + struct hostapd_radius_attr *next; +}; + + +#define NUM_TX_QUEUES 4 + +struct hostapd_tx_queue_params { + int aifs; + int cwmin; + int cwmax; + int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */ +}; + + +#define MAX_ROAMING_CONSORTIUM_LEN 15 + +struct hostapd_roaming_consortium { + u8 len; + u8 oi[MAX_ROAMING_CONSORTIUM_LEN]; +}; + +struct hostapd_lang_string { + u8 lang[3]; + u8 name_len; + u8 name[252]; +}; + +#define MAX_NAI_REALMS 10 +#define MAX_NAI_REALMLEN 255 +#define MAX_NAI_EAP_METHODS 5 +#define MAX_NAI_AUTH_TYPES 4 +struct hostapd_nai_realm_data { + u8 encoding; + char realm_buf[MAX_NAI_REALMLEN + 1]; + char *realm[MAX_NAI_REALMS]; + u8 eap_method_count; + struct hostapd_nai_realm_eap { + u8 eap_method; + u8 num_auths; + u8 auth_id[MAX_NAI_AUTH_TYPES]; + u8 auth_val[MAX_NAI_AUTH_TYPES]; + } eap_method[MAX_NAI_EAP_METHODS]; +}; +#endif + +/** + * struct hostapd_bss_config - Per-BSS configuration + */ +struct hostapd_bss_config { +// char iface[IFNAMSIZ + 1]; +// char bridge[IFNAMSIZ + 1]; +// char wds_bridge[IFNAMSIZ + 1]; + +// enum hostapd_logger_level logger_syslog_level, logger_stdout_level; + +// unsigned int logger_syslog; /* module bitfield */ +// unsigned int logger_stdout; /* module bitfield */ + +// char *dump_log_name; /* file name for state dump (SIGUSR1) */ + + int max_num_sta; /* maximum number of STAs in station table */ + + int dtim_period; + + int ieee802_1x; /* use IEEE 802.1X */ + int eapol_version; +// int eap_server; /* Use internal EAP server instead of external +// * RADIUS server */ +// struct hostapd_eap_user *eap_user; +// char *eap_user_sqlite; +// char *eap_sim_db; +// struct hostapd_ip_addr own_ip_addr; +// char *nas_identifier; +// struct hostapd_radius_servers *radius; +// int acct_interim_interval; +// int radius_request_cui; +// struct hostapd_radius_attr *radius_auth_req_attr; +// struct hostapd_radius_attr *radius_acct_req_attr; +// int radius_das_port; +// unsigned int radius_das_time_window; +// int radius_das_require_event_timestamp; +// struct hostapd_ip_addr radius_das_client_addr; +// u8 *radius_das_shared_secret; +// size_t radius_das_shared_secret_len; + + struct hostapd_ssid ssid; + +// char *eap_req_id_text; /* optional displayable message sent with +// * EAP Request-Identity */ +// size_t eap_req_id_text_len; +// int eapol_key_index_workaround; + +// size_t default_wep_key_len; +// int individual_wep_key_len; + int wep_rekeying_period; + int broadcast_key_idx_min, broadcast_key_idx_max; +// int eap_reauth_period; + +// int ieee802_11f; /* use IEEE 802.11f (IAPP) */ +// char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast +// * frames */ + + enum { + ACCEPT_UNLESS_DENIED = 0, + DENY_UNLESS_ACCEPTED = 1, + USE_EXTERNAL_RADIUS_AUTH = 2 + } macaddr_acl; +// struct mac_acl_entry *accept_mac; +// int num_accept_mac; +// struct mac_acl_entry *deny_mac; +// int num_deny_mac; +// int wds_sta; +// int isolate; + + int auth_algs; /* bitfield of allowed IEEE 802.11 authentication + * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ + + int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ + int wpa_key_mgmt; +#ifdef CONFIG_IEEE80211W + enum mfp_options ieee80211w; + /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ + unsigned int assoc_sa_query_max_timeout; + /* dot11AssociationSAQueryRetryTimeout (in TUs) */ + int assoc_sa_query_retry_timeout; +#endif /* CONFIG_IEEE80211W */ + enum { + PSK_RADIUS_IGNORED = 0, + PSK_RADIUS_ACCEPTED = 1, + PSK_RADIUS_REQUIRED = 2 + } wpa_psk_radius; + int wpa_pairwise; + int wpa_group; + int wpa_group_rekey; + int wpa_strict_rekey; + int wpa_gmk_rekey; + int wpa_ptk_rekey; + int rsn_pairwise; + int rsn_preauth; + char *rsn_preauth_interfaces; + int peerkey; + +#ifdef CONFIG_IEEE80211R + /* IEEE 802.11r - Fast BSS Transition */ + u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; + u8 r1_key_holder[FT_R1KH_ID_LEN]; + u32 r0_key_lifetime; + u32 reassociation_deadline; + struct ft_remote_r0kh *r0kh_list; + struct ft_remote_r1kh *r1kh_list; + int pmk_r1_push; + int ft_over_ds; +#endif /* CONFIG_IEEE80211R */ + +// char *ctrl_interface; /* directory for UNIX domain sockets */ +#ifndef CONFIG_NATIVE_WINDOWS +// gid_t ctrl_interface_gid; +#endif /* CONFIG_NATIVE_WINDOWS */ +// int ctrl_interface_gid_set; + +// char *ca_cert; +// char *server_cert; +// char *private_key; +// char *private_key_passwd; +// int check_crl; +// char *dh_file; +// u8 *pac_opaque_encr_key; +// u8 *eap_fast_a_id; +// size_t eap_fast_a_id_len; +// char *eap_fast_a_id_info; +// int eap_fast_prov; +// int pac_key_lifetime; +// int pac_key_refresh_time; +// int eap_sim_aka_result_ind; +// int tnc; +// int fragment_size; +// u16 pwd_group; + +// char *radius_server_clients; +// int radius_server_auth_port; +// int radius_server_ipv6; + +// char *test_socket; /* UNIX domain socket path for driver_test */ + +// int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group +// * address instead of individual address +// * (for driver_wired.c). +// */ + + int ap_max_inactivity; + int ignore_broadcast_ssid; + + int wmm_enabled; + int wmm_uapsd; + +// struct hostapd_vlan *vlan, *vlan_tail; + + macaddr bssid; + + /* + * Maximum listen interval that STAs can use when associating with this + * BSS. If a STA tries to use larger value, the association will be + * denied with status code 51. + */ + u16 max_listen_interval; + +// int disable_pmksa_caching; +// int okc; /* Opportunistic Key Caching */ + +// int wps_state; +#ifdef CONFIG_WPS + int ap_setup_locked; + u8 uuid[16]; + char *wps_pin_requests; + char *device_name; + char *manufacturer; + char *model_name; + char *model_number; + char *serial_number; + u8 device_type[WPS_DEV_TYPE_LEN]; + char *config_methods; + u8 os_version[4]; + char *ap_pin; + int skip_cred_build; + u8 *extra_cred; + size_t extra_cred_len; + int wps_cred_processing; + u8 *ap_settings; + size_t ap_settings_len; + char *upnp_iface; + char *friendly_name; + char *manufacturer_url; + char *model_description; + char *model_url; + char *upc; + struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; + int wps_nfc_dev_pw_id; + struct wpabuf *wps_nfc_dh_pubkey; + struct wpabuf *wps_nfc_dh_privkey; + struct wpabuf *wps_nfc_dev_pw; +#endif /* CONFIG_WPS */ +// int pbc_in_m1; + +#define P2P_ENABLED BIT(0) +#define P2P_GROUP_OWNER BIT(1) +#define P2P_GROUP_FORMATION BIT(2) +#define P2P_MANAGE BIT(3) +#define P2P_ALLOW_CROSS_CONNECTION BIT(4) +// int p2p; + +// int disassoc_low_ack; +// int skip_inactivity_poll; + +#define TDLS_PROHIBIT BIT(0) +#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1) +// int tdls; +// int disable_11n; +// int disable_11ac; + + /* IEEE 802.11v */ +// int time_advertisement; +// char *time_zone; +// int wnm_sleep_mode; +// int bss_transition; + + /* IEEE 802.11u - Interworking */ +// int interworking; +// int access_network_type; +// int internet; +// int asra; +// int esr; +// int uesa; +// int venue_info_set; +// u8 venue_group; +// u8 venue_type; +// u8 hessid[ETH_ALEN]; + + /* IEEE 802.11u - Roaming Consortium list */ +// unsigned int roaming_consortium_count; +// struct hostapd_roaming_consortium *roaming_consortium; + + /* IEEE 802.11u - Venue Name duples */ +// unsigned int venue_name_count; +// struct hostapd_lang_string *venue_name; + + /* IEEE 802.11u - Network Authentication Type */ +// u8 *network_auth_type; +// size_t network_auth_type_len; + + /* IEEE 802.11u - IP Address Type Availability */ +// u8 ipaddr_type_availability; +// u8 ipaddr_type_configured; + + /* IEEE 802.11u - 3GPP Cellular Network */ +// u8 *anqp_3gpp_cell_net; +// size_t anqp_3gpp_cell_net_len; + + /* IEEE 802.11u - Domain Name */ +// u8 *domain_name; +// size_t domain_name_len; + +// unsigned int nai_realm_count; +// struct hostapd_nai_realm_data *nai_realm_data; + +// u16 gas_comeback_delay; +// int gas_frag_limit; + +#ifdef CONFIG_HS20 + int hs20; + int disable_dgaf; + unsigned int hs20_oper_friendly_name_count; + struct hostapd_lang_string *hs20_oper_friendly_name; + u8 *hs20_wan_metrics; + u8 *hs20_connection_capability; + size_t hs20_connection_capability_len; + u8 *hs20_operating_class; + u8 hs20_operating_class_len; +#endif /* CONFIG_HS20 */ + +// u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */ + +#ifdef CONFIG_RADIUS_TEST + char *dump_msk_file; +#endif /* CONFIG_RADIUS_TEST */ + +// struct wpabuf *vendor_elements; +}; + + +/** + * struct hostapd_config - Per-radio interface configuration + */ +struct hostapd_config { + struct hostapd_bss_config *bss, *last_bss; + size_t num_bss; + + u16 beacon_int; + int rts_threshold; + int fragm_threshold; + u8 send_probe_response; + u8 channel; + enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ + enum { + LONG_PREAMBLE = 0, + SHORT_PREAMBLE = 1 + } preamble; + + int *supported_rates; + int *basic_rates; + + const struct wpa_driver_ops *driver; + + int ap_table_max_size; + int ap_table_expiration_time; + + char country[3]; /* first two octets: country code as described in + * ISO/IEC 3166-1. Third octet: + * ' ' (ascii 32): all environments + * 'O': Outdoor environemnt only + * 'I': Indoor environment only + */ + + int ieee80211d; + +// struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES]; + + /* + * WMM AC parameters, in same order as 802.1D, i.e. + * 0 = BE (best effort) + * 1 = BK (background) + * 2 = VI (video) + * 3 = VO (voice) + */ +// struct hostapd_wmm_ac_params wmm_ac_params[4]; + + int ht_op_mode_fixed; + u16 ht_capab; + int ieee80211n; + int secondary_channel; + int require_ht; + u32 vht_capab; + int ieee80211ac; + int require_vht; + u8 vht_oper_chwidth; + u8 vht_oper_centr_freq_seg0_idx; + u8 vht_oper_centr_freq_seg1_idx; +}; + + +int hostapd_mac_comp(const void *a, const void *b); +int hostapd_mac_comp_empty(const void *a); +struct hostapd_config * hostapd_config_defaults(void); +void hostapd_config_defaults_bss(struct hostapd_bss_config *bss); +void hostapd_config_free(struct hostapd_config *conf); +int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, + const u8 *addr, int *vlan_id); +int hostapd_rate_found(int *list, int rate); +int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, + struct hostapd_wep_keys *b); +const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, + const u8 *addr, const u8 *prev_psk); +int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf); +//const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, +// int vlan_id); +//struct hostapd_radius_attr * +//hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type); + +#endif /* HOSTAPD_CONFIG_H */ diff --git a/components/wpa_supplicant/include/wpa/common.h b/components/wpa_supplicant/include/wpa/common.h new file mode 100644 index 0000000000..ca80c2394f --- /dev/null +++ b/components/wpa_supplicant/include/wpa/common.h @@ -0,0 +1,324 @@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(__ets__) +#endif /* ets */ +#include "os.h" + +#if defined(__XTENSA__) +#include +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#endif /*__XTENSA__*/ + +#if defined(__linux__) || defined(__GLIBC__) || defined(__ets__) +#include +#include +#endif /* __linux__ */ + +/* Define platform specific byte swapping macros */ + +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) + +static inline unsigned short wpa_swap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int wpa_swap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} + +#define le_to_host16(n) (n) +#define host_to_le16(n) (n) +#define be_to_host16(n) wpa_swap_16(n) +#define host_to_be16(n) wpa_swap_16(n) +#define le_to_host32(n) (n) +#define be_to_host32(n) wpa_swap_32(n) +#define host_to_be32(n) wpa_swap_32(n) + +#define WPA_BYTE_SWAP_DEFINED + +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ + + +#ifndef WPA_BYTE_SWAP_DEFINED + +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#if defined(sparc) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* __BIG_ENDIAN */ +#endif /* __LITTLE_ENDIAN */ +#endif /* __BYTE_ORDER */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le_to_host16(n) ((__force u16) (le16) (n)) +#define host_to_le16(n) ((__force le16) (u16) (n)) +#define be_to_host16(n) __bswap_16((__force u16) (be16) (n)) +#define host_to_be16(n) ((__force be16) __bswap_16((n))) +#define le_to_host32(n) ((__force u32) (le32) (n)) +#define host_to_le32(n) ((__force le32) (u32) (n)) +#define be_to_host32(n) __bswap_32((__force u32) (be32) (n)) +#define host_to_be32(n) ((__force be32) __bswap_32((n))) +#define le_to_host64(n) ((__force u64) (le64) (n)) +#define host_to_le64(n) ((__force le64) (u64) (n)) +#define be_to_host64(n) __bswap_64((__force u64) (be64) (n)) +#define host_to_be64(n) ((__force be64) bswap_64((n))) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define le_to_host16(n) __bswap_16(n) +#define host_to_le16(n) __bswap_16(n) +#define be_to_host16(n) (n) +#define host_to_be16(n) (n) +#define le_to_host32(n) __bswap_32(n) +#define be_to_host32(n) (n) +#define host_to_be32(n) (n) +#define le_to_host64(n) __bswap_64(n) +#define host_to_le64(n) __bswap_64(n) +#define be_to_host64(n) (n) +#define host_to_be64(n) (n) +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#else +#error Could not determine CPU byte order +#endif + +#define WPA_BYTE_SWAP_DEFINED +#endif /* !WPA_BYTE_SWAP_DEFINED */ + + +/* Macros for handling unaligned memory accesses */ + +#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) +#define WPA_PUT_BE16(a, val) \ + do { \ + (a)[0] = ((u16) (val)) >> 8; \ + (a)[1] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define WPA_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ + ((u32) (a)[2])) +#define WPA_PUT_BE24(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[2] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ + (((u32) (a)[2]) << 8) | ((u32) (a)[3])) +#define WPA_PUT_BE32(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[3] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ + (((u32) (a)[1]) << 8) | ((u32) (a)[0])) +#define WPA_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ + (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ + (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ + (((u64) (a)[6]) << 8) | ((u64) (a)[7])) +#define WPA_PUT_BE64(a, val) \ + do { \ + (a)[0] = (u8) (((u64) (val)) >> 56); \ + (a)[1] = (u8) (((u64) (val)) >> 48); \ + (a)[2] = (u8) (((u64) (val)) >> 40); \ + (a)[3] = (u8) (((u64) (val)) >> 32); \ + (a)[4] = (u8) (((u64) (val)) >> 24); \ + (a)[5] = (u8) (((u64) (val)) >> 16); \ + (a)[6] = (u8) (((u64) (val)) >> 8); \ + (a)[7] = (u8) (((u64) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ + (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ + (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ + (((u64) (a)[1]) << 8) | ((u64) (a)[0])) + + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif +//#ifndef IFNAMSIZ +//#define IFNAMSIZ 16 +//#endif +#ifndef ETH_P_ALL +#define ETH_P_ALL 0x0003 +#endif +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ +#ifndef ETH_P_EAPOL +#define ETH_P_EAPOL ETH_P_PAE +#endif /* ETH_P_EAPOL */ +#ifndef ETH_P_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif /* ETH_P_RSN_PREAUTH */ +#ifndef ETH_P_RRB +#define ETH_P_RRB 0x890D +#endif /* ETH_P_RRB */ + + +#ifdef __GNUC__ +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) +#define STRUCT_PACKED __attribute__ ((packed)) +#else +#define PRINTF_FORMAT(a,b) +#define STRUCT_PACKED +#endif + +#ifdef CONFIG_ANSI_C_EXTRA + +/* inline - define as __inline or just define it to be empty, if needed */ +#ifdef CONFIG_NO_INLINE +#define inline +#else +#define inline __inline +#endif + +#ifndef __func__ +#define __func__ "__func__ not defined" +#endif + +#ifndef bswap_16 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) +#endif + +#ifndef bswap_32 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ + (((u32) (a) << 8) & 0xff0000) | \ + (((u32) (a) >> 8) & 0xff00) | \ + (((u32) (a) >> 24) & 0xff)) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +#ifdef _WIN32_WCE +void perror(const char *s); +#endif /* _WIN32_WCE */ + +#endif /* CONFIG_ANSI_C_EXTRA */ + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#endif + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +/* + * Definitions for sparse validation + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) + */ +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef u16 __bitwise be16; +typedef u16 __bitwise le16; +typedef u32 __bitwise be32; +typedef u32 __bitwise le32; +typedef u64 __bitwise be64; +typedef u64 __bitwise le64; + +#ifndef __must_check +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __must_check __attribute__((__warn_unused_result__)) +#else +#define __must_check +#endif /* __GNUC__ */ +#endif /* __must_check */ + +int hwaddr_aton(const char *txt, u8 *addr); +int hwaddr_aton2(const char *txt, u8 *addr); +int hexstr2bin(const char *hex, u8 *buf, size_t len); +void inc_byte_array(u8 *counter, size_t len); +void wpa_get_ntp_timestamp(u8 *buf); +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + +#ifdef CONFIG_NATIVE_WINDOWS +void wpa_unicode2ascii_inplace(TCHAR *str); +TCHAR * wpa_strdup_tchar(const char *str); +#else /* CONFIG_NATIVE_WINDOWS */ +#define wpa_unicode2ascii_inplace(s) do { } while (0) +#define wpa_strdup_tchar(s) strdup((s)) +#endif /* CONFIG_NATIVE_WINDOWS */ + +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); +char * wpa_config_parse_string(const char *value, size_t *len); + +static inline int is_zero_ether_addr(const u8 *a) +{ + return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); +} + +extern const struct eth_addr ethbroadcast; +#define broadcast_ether_addr ðbroadcast + +#include "wpabuf.h" +#include "wpa_debug.h" + + +/* + * gcc 4.4 ends up generating strict-aliasing warnings about some very common + * networking socket uses that do not really result in a real problem and + * cannot be easily avoided with union-based type-punning due to struct + * definitions including another struct in system header files. To avoid having + * to fully disable strict-aliasing warnings, provide a mechanism to hide the + * typecast from aliasing for now. A cleaner solution will hopefully be found + * in the future to handle these cases. + */ +void * __hide_aliasing_typecast(void *foo); +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) + +#endif /* COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa/defs.h b/components/wpa_supplicant/include/wpa/defs.h new file mode 100644 index 0000000000..f019cee992 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/defs.h @@ -0,0 +1,307 @@ +/* + * WPA Supplicant - Common definitions + * Copyright (c) 2004-2008, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef DEFS_H +#define DEFS_H + +#ifdef FALSE +#undef FALSE +#endif +#ifdef TRUE +#undef TRUE +#endif +typedef enum { FALSE = 0, TRUE = 1 } Boolean; + +/* +#define WPA_CIPHER_NONE BIT(0) +#define WPA_CIPHER_WEP40 BIT(1) +#define WPA_CIPHER_WEP104 BIT(2) +#define WPA_CIPHER_TKIP BIT(3) +#define WPA_CIPHER_CCMP BIT(4) +#ifdef CONFIG_IEEE80211W +#define WPA_CIPHER_AES_128_CMAC BIT(5) +#endif +*/ + +/* + * NB: these values are ordered carefully; there are lots of + * of implications in any reordering. Beware that 4 is used + * only to indicate h/w TKIP MIC support in driver capabilities; + * there is no separate cipher support (it's rolled into the + * TKIP cipher support). + */ +#define IEEE80211_CIPHER_NONE 0 /* pseudo value */ +#define IEEE80211_CIPHER_TKIP 1 +#define IEEE80211_CIPHER_AES_OCB 2 +#define IEEE80211_CIPHER_AES_CCM 3 +#define IEEE80211_CIPHER_TKIPMIC 4 /* TKIP MIC capability */ +#define IEEE80211_CIPHER_CKIP 5 +#define IEEE80211_CIPHER_WEP 6 +#define IEEE80211_CIPHER_WEP40 7 +#define IEEE80211_CIPHER_WEP104 8 + + +#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+2) + +/* capability bits in ic_cryptocaps/iv_cryptocaps */ +#define IEEE80211_CRYPTO_NONE (1<wpa_state). The current state can be retrieved with + * wpa_supplicant_get_state() function and the state can be changed by calling + * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the + * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used + * to access the state variable. + */ +enum wpa_states { + /** + * WPA_DISCONNECTED - Disconnected state + * + * This state indicates that client is not associated, but is likely to + * start looking for an access point. This state is entered when a + * connection is lost. + */ + WPA_DISCONNECTED, + + /** + * WPA_INACTIVE - Inactive state (wpa_supplicant disabled) + * + * This state is entered if there are no enabled networks in the + * configuration. wpa_supplicant is not trying to associate with a new + * network and external interaction (e.g., ctrl_iface call to add or + * enable a network) is needed to start association. + */ + WPA_INACTIVE, + + /** + * WPA_SCANNING - Scanning for a network + * + * This state is entered when wpa_supplicant starts scanning for a + * network. + */ + WPA_SCANNING, + + /** + * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID + * + * This state is entered when wpa_supplicant has found a suitable BSS + * to authenticate with and the driver is configured to try to + * authenticate with this BSS. This state is used only with drivers + * that use wpa_supplicant as the SME. + */ + WPA_AUTHENTICATING, + + /** + * WPA_ASSOCIATING - Trying to associate with a BSS/SSID + * + * This state is entered when wpa_supplicant has found a suitable BSS + * to associate with and the driver is configured to try to associate + * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this + * state is entered when the driver is configured to try to associate + * with a network using the configured SSID and security policy. + */ + WPA_ASSOCIATING, + + /** + * WPA_ASSOCIATED - Association completed + * + * This state is entered when the driver reports that association has + * been successfully completed with an AP. If IEEE 802.1X is used + * (with or without WPA/WPA2), wpa_supplicant remains in this state + * until the IEEE 802.1X/EAPOL authentication has been completed. + */ + WPA_ASSOCIATED, + + /** + * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress + * + * This state is entered when WPA/WPA2 4-Way Handshake is started. In + * case of WPA-PSK, this happens when receiving the first EAPOL-Key + * frame after association. In case of WPA-EAP, this state is entered + * when the IEEE 802.1X/EAPOL authentication has been completed. + */ + WPA_FIRST_HALF_4WAY_HANDSHAKE, + + WPA_LAST_HALF_4WAY_HANDSHAKE, + + /** + * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress + * + * This state is entered when 4-Way Key Handshake has been completed + * (i.e., when the supplicant sends out message 4/4) and when Group + * Key rekeying is started by the AP (i.e., when supplicant receives + * message 1/2). + */ + WPA_GROUP_HANDSHAKE, + + /** + * WPA_COMPLETED - All authentication completed + * + * This state is entered when the full authentication process is + * completed. In case of WPA2, this happens when the 4-Way Handshake is + * successfully completed. With WPA, this state is entered after the + * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is + * completed after dynamic keys are received (or if not used, after + * the EAP authentication has been completed). With static WEP keys and + * plaintext connections, this state is entered when an association + * has been completed. + * + * This state indicates that the supplicant has completed its + * processing for the association phase and that data connection is + * fully configured. + */ + WPA_COMPLETED, + + WPA_MIC_FAILURE, // first mic_error event occur + + WPA_TKIP_COUNTERMEASURES //in countermeasure period that stop connect with ap in 60 sec +}; + +#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0 +#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1 +#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2 +#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3 + +#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0 +#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1 + +/** + * enum hostapd_hw_mode - Hardware mode + */ +enum hostapd_hw_mode { + HOSTAPD_MODE_IEEE80211B, + HOSTAPD_MODE_IEEE80211G, + HOSTAPD_MODE_IEEE80211A, + HOSTAPD_MODE_IEEE80211AD, + NUM_HOSTAPD_MODES +}; + +#endif /* DEFS_H */ diff --git a/components/wpa_supplicant/include/wpa/eapol_common.h b/components/wpa_supplicant/include/wpa/eapol_common.h new file mode 100644 index 0000000000..6a40ac33b3 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/eapol_common.h @@ -0,0 +1,71 @@ +/* + * EAPOL definitions shared between hostapd and wpa_supplicant + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef EAPOL_COMMON_H +#define EAPOL_COMMON_H + +/* IEEE Std 802.1X-2004 */ + +struct ieee802_1x_hdr { + u8 version; + u8 type; + be16 length; + /* followed by length octets of data */ +} STRUCT_PACKED; + + +#define EAPOL_VERSION 2 + +enum { IEEE802_1X_TYPE_EAP_PACKET = 0, + IEEE802_1X_TYPE_EAPOL_START = 1, + IEEE802_1X_TYPE_EAPOL_LOGOFF = 2, + IEEE802_1X_TYPE_EAPOL_KEY = 3, + IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4 +}; + +enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2, + EAPOL_KEY_TYPE_WPA = 254 }; + +#define IEEE8021X_REPLAY_COUNTER_LEN 8 +#define IEEE8021X_KEY_SIGN_LEN 16 +#define IEEE8021X_KEY_IV_LEN 16 + +#define IEEE8021X_KEY_INDEX_FLAG 0x80 +#define IEEE8021X_KEY_INDEX_MASK 0x03 + +struct ieee802_1x_eapol_key { + u8 type; + /* Note: key_length is unaligned */ + u8 key_length[2]; + /* does not repeat within the life of the keying material used to + * encrypt the Key field; 64-bit NTP timestamp MAY be used here */ + u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN]; + u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */ + u8 key_index; /* key flag in the most significant bit: + * 0 = broadcast (default key), + * 1 = unicast (key mapping key); key index is in the + * 7 least significant bits */ + /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as + * the key */ + u8 key_signature[IEEE8021X_KEY_SIGN_LEN]; + + /* followed by key: if packet body length = 44 + key length, then the + * key field (of key_length bytes) contains the key in encrypted form; + * if packet body length = 44, key field is absent and key_length + * represents the number of least significant octets from + * MS-MPPE-Send-Key attribute to be used as the keying material; + * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */ +} STRUCT_PACKED; + +#endif /* EAPOL_COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa/hostapd.h b/components/wpa_supplicant/include/wpa/hostapd.h new file mode 100644 index 0000000000..1d52659a22 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/hostapd.h @@ -0,0 +1,312 @@ +/* + * hostapd / Initialization and configuration + * Copyright (c) 2002-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef HOSTAPD_H +#define HOSTAPD_H + +#include "wpa/defs.h" +#include "wpa/ap_config.h" + +struct wpa_driver_ops; +struct wpa_ctrl_dst; +struct radius_server_data; +struct upnp_wps_device_sm; +struct hostapd_data; +struct sta_info; +struct hostap_sta_driver_data; +struct ieee80211_ht_capabilities; +struct full_dynamic_vlan; +enum wps_event; +union wps_event_data; + +struct hostapd_iface; + +struct hapd_interfaces { + int (*reload_config)(struct hostapd_iface *iface); + struct hostapd_config * (*config_read_cb)(const char *config_fname); + int (*ctrl_iface_init)(struct hostapd_data *hapd); + void (*ctrl_iface_deinit)(struct hostapd_data *hapd); + int (*for_each_interface)(struct hapd_interfaces *interfaces, + int (*cb)(struct hostapd_iface *iface, + void *ctx), void *ctx); + int (*driver_init)(struct hostapd_iface *iface); + + size_t count; + int global_ctrl_sock; + char *global_iface_path; + char *global_iface_name; + struct hostapd_iface **iface; +}; + + +struct hostapd_probereq_cb { + int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid, + const u8 *ie, size_t ie_len, int ssi_signal); + void *ctx; +}; + +#define HOSTAPD_RATE_BASIC 0x00000001 + +struct hostapd_rate_data { + int rate; /* rate in 100 kbps */ + int flags; /* HOSTAPD_RATE_ flags */ +}; + +struct hostapd_frame_info { + u32 channel; + u32 datarate; + int ssi_signal; /* dBm */ +}; + + +/** + * struct hostapd_data - hostapd per-BSS data structure + */ +struct hostapd_data { +// struct hostapd_iface *iface; + struct hostapd_config *iconf; + struct hostapd_bss_config *conf; + int interface_added; /* virtual interface added for this BSS */ + + u8 own_addr[ETH_ALEN]; + + int num_sta; /* number of entries in sta_list */ +// struct sta_info *sta_list; /* STA info list head */ +//#define STA_HASH_SIZE 256 +//#define STA_HASH(sta) (sta[5]) +// struct sta_info *sta_hash[STA_HASH_SIZE]; + +// /* +// * Bitfield for indicating which AIDs are allocated. Only AID values +// * 1-2007 are used and as such, the bit at index 0 corresponds to AID +// * 1. +// */ +//#define AID_WORDS ((2008 + 31) / 32) +// u32 sta_aid[AID_WORDS]; + +// const struct wpa_driver_ops *driver; +// void *drv_priv; + +// void (*new_assoc_sta_cb)(struct hostapd_data *hapd, +// struct sta_info *sta, int reassoc); + +// void *msg_ctx; /* ctx for wpa_msg() calls */ +// void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */ + +// struct radius_client_data *radius; +// u32 acct_session_id_hi, acct_session_id_lo; +// struct radius_das_data *radius_das; + +// struct iapp_data *iapp; + +// struct hostapd_cached_radius_acl *acl_cache; +// struct hostapd_acl_query_data *acl_queries; + + struct wpa_authenticator *wpa_auth; +// struct eapol_authenticator *eapol_auth; + +// struct rsn_preauth_interface *preauth_iface; +// time_t michael_mic_failure; +// int michael_mic_failures; +// int tkip_countermeasures; + +// int ctrl_sock; +// struct wpa_ctrl_dst *ctrl_dst; + +// void *ssl_ctx; +// void *eap_sim_db_priv; +// struct radius_server_data *radius_srv; + +// int parameter_set_count; + + /* Time Advertisement */ +// u8 time_update_counter; +// struct wpabuf *time_adv; + +#ifdef CONFIG_FULL_DYNAMIC_VLAN + struct full_dynamic_vlan *full_dynamic_vlan; +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ + +// struct l2_packet_data *l2; +// struct wps_context *wps; + +// int beacon_set_done; +// struct wpabuf *wps_beacon_ie; +// struct wpabuf *wps_probe_resp_ie; +#ifdef CONFIG_WPS + unsigned int ap_pin_failures; + unsigned int ap_pin_failures_consecutive; + struct upnp_wps_device_sm *wps_upnp; + unsigned int ap_pin_lockout_time; +#endif /* CONFIG_WPS */ + +// struct hostapd_probereq_cb *probereq_cb; +// size_t num_probereq_cb; + +// void (*public_action_cb)(void *ctx, const u8 *buf, size_t len, +// int freq); +// void *public_action_cb_ctx; + +// int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len, +// int freq); +// void *vendor_action_cb_ctx; + +// void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr, +// const u8 *uuid_e); +// void *wps_reg_success_cb_ctx; + +// void (*wps_event_cb)(void *ctx, enum wps_event event, +// union wps_event_data *data); +// void *wps_event_cb_ctx; + +// void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr, +// int authorized, const u8 *p2p_dev_addr); +// void *sta_authorized_cb_ctx; + +// void (*setup_complete_cb)(void *ctx); +// void *setup_complete_cb_ctx; + +#ifdef CONFIG_P2P + struct p2p_data *p2p; + struct p2p_group *p2p_group; + struct wpabuf *p2p_beacon_ie; + struct wpabuf *p2p_probe_resp_ie; + + /* Number of non-P2P association stations */ + int num_sta_no_p2p; + + /* Periodic NoA (used only when no non-P2P clients in the group) */ + int noa_enabled; + int noa_start; + int noa_duration; +#endif /* CONFIG_P2P */ +#ifdef CONFIG_INTERWORKING + size_t gas_frag_limit; +#endif /* CONFIG_INTERWORKING */ + +#ifdef CONFIG_SQLITE + struct hostapd_eap_user tmp_eap_user; +#endif /* CONFIG_SQLITE */ +}; + +#if 0 +/** + * struct hostapd_iface - hostapd per-interface data structure + */ +struct hostapd_iface { + struct hapd_interfaces *interfaces; + void *owner; + char *config_fname; + struct hostapd_config *conf; + + size_t num_bss; + struct hostapd_data **bss; + + int num_ap; /* number of entries in ap_list */ + struct ap_info *ap_list; /* AP info list head */ + struct ap_info *ap_hash[STA_HASH_SIZE]; + struct ap_info *ap_iter_list; + + unsigned int drv_flags; + + /* + * A bitmap of supported protocols for probe response offload. See + * struct wpa_driver_capa in driver.h + */ + unsigned int probe_resp_offloads; + + struct hostapd_hw_modes *hw_features; + int num_hw_features; + struct hostapd_hw_modes *current_mode; + /* Rates that are currently used (i.e., filtered copy of + * current_mode->channels */ + int num_rates; + struct hostapd_rate_data *current_rates; + int *basic_rates; + int freq; + + u16 hw_flags; + + /* Number of associated Non-ERP stations (i.e., stations using 802.11b + * in 802.11g BSS) */ + int num_sta_non_erp; + + /* Number of associated stations that do not support Short Slot Time */ + int num_sta_no_short_slot_time; + + /* Number of associated stations that do not support Short Preamble */ + int num_sta_no_short_preamble; + + int olbc; /* Overlapping Legacy BSS Condition */ + + /* Number of HT associated stations that do not support greenfield */ + int num_sta_ht_no_gf; + + /* Number of associated non-HT stations */ + int num_sta_no_ht; + + /* Number of HT associated stations 20 MHz */ + int num_sta_ht_20mhz; + + /* Overlapping BSS information */ + int olbc_ht; + + u16 ht_op_mode; + void (*scan_cb)(struct hostapd_iface *iface); +}; +#endif + +#if 0 +/* hostapd.c */ +int hostapd_for_each_interface(struct hapd_interfaces *interfaces, + int (*cb)(struct hostapd_iface *iface, + void *ctx), void *ctx); +int hostapd_reload_config(struct hostapd_iface *iface); +struct hostapd_data * +hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, + struct hostapd_config *conf, + struct hostapd_bss_config *bss); +int hostapd_setup_interface(struct hostapd_iface *iface); +int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); +void hostapd_interface_deinit(struct hostapd_iface *iface); +void hostapd_interface_free(struct hostapd_iface *iface); +void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, + int reassoc); +void hostapd_interface_deinit_free(struct hostapd_iface *iface); +int hostapd_enable_iface(struct hostapd_iface *hapd_iface); +int hostapd_reload_iface(struct hostapd_iface *hapd_iface); +int hostapd_disable_iface(struct hostapd_iface *hapd_iface); +int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf); +int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf); + +/* utils.c */ +int hostapd_register_probereq_cb(struct hostapd_data *hapd, + int (*cb)(void *ctx, const u8 *sa, + const u8 *da, const u8 *bssid, + const u8 *ie, size_t ie_len, + int ssi_signal), + void *ctx); +void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); + +/* drv_callbacks.c (TODO: move to somewhere else?) */ +int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, + const u8 *ie, size_t ielen, int reassoc); +void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); +void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr); +int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, + const u8 *bssid, const u8 *ie, size_t ie_len, + int ssi_signal); +void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, + int offset); + +const struct hostapd_eap_user * +hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, + size_t identity_len, int phase2); +#endif + +#endif /* HOSTAPD_H */ diff --git a/components/wpa_supplicant/include/wpa/ieee80211_crypto.h b/components/wpa_supplicant/include/wpa/ieee80211_crypto.h new file mode 100644 index 0000000000..be0fb9aa12 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/ieee80211_crypto.h @@ -0,0 +1,226 @@ +/*- + * Copyright (c) 2001 Atsushi Onoe + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * copyright (c) 2010-2011 Espressif System + */ +#ifndef _NET80211_IEEE80211_CRYPTO_H_ +#define _NET80211_IEEE80211_CRYPTO_H_ + +//#include "pp/esf_buf.h" + +/* + * 802.11 protocol crypto-related definitions. + */ +#define IEEE80211_KEYBUF_SIZE 16 +#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx+rx keys */ + +/* + * Old WEP-style key. Deprecated. + */ + +#if 0 +struct ieee80211_rsnparms { + uint8_t rsn_mcastcipher; /* mcast/group cipher */ + uint8_t rsn_mcastkeylen; /* mcast key length */ + uint8_t rsn_ucastcipher; /* selected unicast cipher */ + uint8_t rsn_ucastkeylen; /* unicast key length */ + uint8_t rsn_keymgmt; /* selected key mgmt algo */ + uint16_t rsn_caps; /* capabilities */ +}; +#endif //0000 + +/* + * Template for a supported cipher. Ciphers register with the + * crypto code and are typically loaded as separate modules + * (the null cipher is always present). + * XXX may need refcnts + */ + +/* + * Crypto key state. There is sufficient room for all supported + * ciphers (see below). The underlying ciphers are handled + * separately through loadable cipher modules that register with + * the generic crypto support. A key has a reference to an instance + * of the cipher; any per-key state is hung off wk_private by the + * cipher when it is attached. Ciphers are automatically called + * to detach and cleanup any such state when the key is deleted. + * + * The generic crypto support handles encap/decap of cipher-related + * frame contents for both hardware- and software-based implementations. + * A key requiring software crypto support is automatically flagged and + * the cipher is expected to honor this and do the necessary work. + * Ciphers such as TKIP may also support mixed hardware/software + * encrypt/decrypt and MIC processing. + */ +typedef uint16_t ieee80211_keyix; /* h/w key index */ + +struct ieee80211_key { + uint8_t wk_keylen; /* key length in bytes */ + uint8_t wk_pad; + uint16_t wk_flags; +#define IEEE80211_KEY_XMIT 0x0001 /* key used for xmit */ +#define IEEE80211_KEY_RECV 0x0002 /* key used for recv */ +#define IEEE80211_KEY_GROUP 0x0004 /* key used for WPA group operation */ +#define IEEE80211_KEY_SWENCRYPT 0x0010 /* host-based encrypt */ +#define IEEE80211_KEY_SWDECRYPT 0x0020 /* host-based decrypt */ +#define IEEE80211_KEY_SWENMIC 0x0040 /* host-based enmic */ +#define IEEE80211_KEY_SWDEMIC 0x0080 /* host-based demic */ +#define IEEE80211_KEY_DEVKEY 0x0100 /* device key request completed */ +#define IEEE80211_KEY_CIPHER0 0x1000 /* cipher-specific action 0 */ +#define IEEE80211_KEY_CIPHER1 0x2000 /* cipher-specific action 1 */ +#define IEEE80211_KEY_EMPTY 0x0000 + ieee80211_keyix wk_keyix; /* h/w key index */ + ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */ + uint8_t wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE]; +#define wk_txmic wk_key+IEEE80211_KEYBUF_SIZE+0 /* XXX can't () right */ +#define wk_rxmic wk_key+IEEE80211_KEYBUF_SIZE+8 /* XXX can't () right */ + /* key receive sequence counter */ + uint64_t wk_keyrsc[IEEE80211_TID_SIZE]; + uint64_t wk_keytsc; /* key transmit sequence counter */ + const struct ieee80211_cipher *wk_cipher; + //void *wk_private; /* private cipher state */ + //uint8_t wk_macaddr[IEEE80211_ADDR_LEN]; //JLU: no need ... +}; +#define IEEE80211_KEY_COMMON /* common flags passed in by apps */\ + (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV | IEEE80211_KEY_GROUP) +#define IEEE80211_KEY_DEVICE /* flags owned by device driver */\ + (IEEE80211_KEY_DEVKEY|IEEE80211_KEY_CIPHER0|IEEE80211_KEY_CIPHER1) + +#define IEEE80211_KEY_SWCRYPT \ + (IEEE80211_KEY_SWENCRYPT | IEEE80211_KEY_SWDECRYPT) +#define IEEE80211_KEY_SWMIC (IEEE80211_KEY_SWENMIC | IEEE80211_KEY_SWDEMIC) + +//#define IEEE80211_KEYIX_NONE ((ieee80211_keyix) -1) + +/* + * NB: these values are ordered carefully; there are lots of + * of implications in any reordering. Beware that 4 is used + * only to indicate h/w TKIP MIC support in driver capabilities; + * there is no separate cipher support (it's rolled into the + * TKIP cipher support). + */ +#define IEEE80211_CIPHER_NONE 0 /* pseudo value */ +#define IEEE80211_CIPHER_TKIP 1 +#define IEEE80211_CIPHER_AES_OCB 2 +#define IEEE80211_CIPHER_AES_CCM 3 +#define IEEE80211_CIPHER_TKIPMIC 4 /* TKIP MIC capability */ +#define IEEE80211_CIPHER_CKIP 5 +#define IEEE80211_CIPHER_WEP 6 +#define IEEE80211_CIPHER_WEP40 7 +#define IEEE80211_CIPHER_WEP104 8 + + +#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+2) + +/* capability bits in ic_cryptocaps/iv_cryptocaps */ +#define IEEE80211_CRYPTO_NONE (1<wk_cipher == &ieee80211_cipher_none) + +struct ieee80211_key *ieee80211_crypto_encap(struct ieee80211_conn *, + esf_buf *); + +struct ieee80211_key *ieee80211_crypto_decap(struct ieee80211_conn *, + esf_buf *, int); + +#if 0 //H/W MIC +/* + * Check and remove any MIC. + */ +static INLINE int +ieee80211_crypto_demic(struct ieee80211vap *vap, struct ieee80211_key *k, + esf_buf *m, int force) +{ + const struct ieee80211_cipher *cip = k->wk_cipher; + return (cip->ic_miclen > 0 ? cip->ic_demic(k, m, force) : 1); +} + +/* + * Add any MIC. + */ +static INLINE int +ieee80211_crypto_enmic(struct ieee80211vap *vap, + struct ieee80211_key *k, esf_buf *m, int force) +{ + const struct ieee80211_cipher *cip = k->wk_cipher; + return (cip->ic_miclen > 0 ? cip->ic_enmic(k, m, force) : 1); +} +#endif //0000 + +/* + * Setup crypto support for a device/shared instance. + */ +void ieee80211_crypto_attach(struct ieee80211com *ic); + +/* + * Reset key state to an unused state. The crypto + * key allocation mechanism insures other state (e.g. + * key data) is properly setup before a key is used. + */ +static inline void +ieee80211_crypto_resetkey(struct ieee80211_key *k) +{ + k->wk_cipher = NULL; + k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; +} + +/* + * Crypt-related notification methods. + */ +//void ieee80211_notify_replay_failure(const struct ieee80211_frame *, const struct ieee80211_key *, +// uint64_t rsc, int tid); +//void ieee80211_notify_michael_failure(const struct ieee80211_frame *, u_int keyix); + +#endif /* _NET80211_IEEE80211_CRYPTO_H_ */ diff --git a/components/wpa_supplicant/include/wpa/ieee802_11_defs.h b/components/wpa_supplicant/include/wpa/ieee802_11_defs.h new file mode 100644 index 0000000000..4881e39a01 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/ieee802_11_defs.h @@ -0,0 +1,607 @@ +/* + * IEEE 802.11 Frame type definitions + * Copyright (c) 2002-2009, Jouni Malinen + * Copyright (c) 2007-2008 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef IEEE802_11_DEFS_H +#define IEEE802_11_DEFS_H + +/* IEEE 802.11 defines */ + +#define WLAN_FC_PVER 0x0003 +#define WLAN_FC_TODS 0x0100 +#define WLAN_FC_FROMDS 0x0200 +#define WLAN_FC_MOREFRAG 0x0400 +#define WLAN_FC_RETRY 0x0800 +#define WLAN_FC_PWRMGT 0x1000 +#define WLAN_FC_MOREDATA 0x2000 +#define WLAN_FC_ISWEP 0x4000 +#define WLAN_FC_ORDER 0x8000 + +#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2) +#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4) + +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0))) +#define WLAN_GET_SEQ_SEQ(seq) \ + (((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4) + +#define WLAN_FC_TYPE_MGMT 0 +#define WLAN_FC_TYPE_CTRL 1 +#define WLAN_FC_TYPE_DATA 2 + +/* management */ +#define WLAN_FC_STYPE_ASSOC_REQ 0 +#define WLAN_FC_STYPE_ASSOC_RESP 1 +#define WLAN_FC_STYPE_REASSOC_REQ 2 +#define WLAN_FC_STYPE_REASSOC_RESP 3 +#define WLAN_FC_STYPE_PROBE_REQ 4 +#define WLAN_FC_STYPE_PROBE_RESP 5 +#define WLAN_FC_STYPE_BEACON 8 +#define WLAN_FC_STYPE_ATIM 9 +#define WLAN_FC_STYPE_DISASSOC 10 +#define WLAN_FC_STYPE_AUTH 11 +#define WLAN_FC_STYPE_DEAUTH 12 +#define WLAN_FC_STYPE_ACTION 13 + +/* control */ +#define WLAN_FC_STYPE_PSPOLL 10 +#define WLAN_FC_STYPE_RTS 11 +#define WLAN_FC_STYPE_CTS 12 +#define WLAN_FC_STYPE_ACK 13 +#define WLAN_FC_STYPE_CFEND 14 +#define WLAN_FC_STYPE_CFENDACK 15 + +/* data */ +#define WLAN_FC_STYPE_DATA 0 +#define WLAN_FC_STYPE_DATA_CFACK 1 +#define WLAN_FC_STYPE_DATA_CFPOLL 2 +#define WLAN_FC_STYPE_DATA_CFACKPOLL 3 +#define WLAN_FC_STYPE_NULLFUNC 4 +#define WLAN_FC_STYPE_CFACK 5 +#define WLAN_FC_STYPE_CFPOLL 6 +#define WLAN_FC_STYPE_CFACKPOLL 7 +#define WLAN_FC_STYPE_QOS_DATA 8 + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 +#define WLAN_AUTH_FT 2 +#define WLAN_AUTH_LEAP 128 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_ESS BIT(0) +#define WLAN_CAPABILITY_IBSS BIT(1) +#define WLAN_CAPABILITY_CF_POLLABLE BIT(2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3) +#define WLAN_CAPABILITY_PRIVACY BIT(4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5) +#define WLAN_CAPABILITY_PBCC BIT(6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7) +#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8) +#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10) +#define WLAN_CAPABILITY_DSSS_OFDM BIT(13) + +/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ +#define WLAN_STATUS_SUCCESS 0 +#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 +#define WLAN_STATUS_CAPS_UNSUPPORTED 10 +#define WLAN_STATUS_REASSOC_NO_ASSOC 11 +#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 +#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 +#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 +#define WLAN_STATUS_CHALLENGE_FAIL 15 +#define WLAN_STATUS_AUTH_TIMEOUT 16 +#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 +#define WLAN_STATUS_ASSOC_DENIED_RATES 18 +/* IEEE 802.11b */ +#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 +#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 +#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 +/* IEEE 802.11h */ +#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 +#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 +#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 +/* IEEE 802.11g */ +#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 +#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26 +#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27 +#define WLAN_STATUS_R0KH_UNREACHABLE 28 +/* IEEE 802.11w */ +#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 +#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 +#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32 +#define WLAN_STATUS_REQUEST_DECLINED 37 +#define WLAN_STATUS_INVALID_PARAMETERS 38 +/* IEEE 802.11i */ +#define WLAN_STATUS_INVALID_IE 40 +#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 +#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 +#define WLAN_STATUS_AKMP_NOT_VALID 43 +#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 +#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 +#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 +#define WLAN_STATUS_TS_NOT_CREATED 47 +#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 +#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 +#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 +#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 +/* IEEE 802.11r */ +#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 +#define WLAN_STATUS_INVALID_PMKID 53 +#define WLAN_STATUS_INVALID_MDIE 54 +#define WLAN_STATUS_INVALID_FTIE 55 + +/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ +#define WLAN_REASON_UNSPECIFIED 1 +#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 +#define WLAN_REASON_DEAUTH_LEAVING 3 +#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 +#define WLAN_REASON_DISASSOC_AP_BUSY 5 +#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 +#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 +#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 +#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 +/* IEEE 802.11h */ +#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 +#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 +/* IEEE 802.11i */ +#define WLAN_REASON_INVALID_IE 13 +#define WLAN_REASON_MICHAEL_MIC_FAILURE 14 +#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 +#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 +#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 +#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 +#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 +#define WLAN_REASON_AKMP_NOT_VALID 20 +#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 +#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 +#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 +#define WLAN_REASON_CIPHER_SUITE_REJECTED 24 + + +/* Information Element IDs */ +#define WLAN_EID_SSID 0 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_FH_PARAMS 2 +#define WLAN_EID_DS_PARAMS 3 +#define WLAN_EID_CF_PARAMS 4 +#define WLAN_EID_TIM 5 +#define WLAN_EID_IBSS_PARAMS 6 +#define WLAN_EID_COUNTRY 7 +#define WLAN_EID_CHALLENGE 16 +/* EIDs defined by IEEE 802.11h - START */ +#define WLAN_EID_PWR_CONSTRAINT 32 +#define WLAN_EID_PWR_CAPABILITY 33 +#define WLAN_EID_TPC_REQUEST 34 +#define WLAN_EID_TPC_REPORT 35 +#define WLAN_EID_SUPPORTED_CHANNELS 36 +#define WLAN_EID_CHANNEL_SWITCH 37 +#define WLAN_EID_MEASURE_REQUEST 38 +#define WLAN_EID_MEASURE_REPORT 39 +#define WLAN_EID_QUITE 40 +#define WLAN_EID_IBSS_DFS 41 +/* EIDs defined by IEEE 802.11h - END */ +#define WLAN_EID_ERP_INFO 42 +#define WLAN_EID_HT_CAP 45 +#define WLAN_EID_RSN 48 +#define WLAN_EID_EXT_SUPP_RATES 50 +#define WLAN_EID_MOBILITY_DOMAIN 54 +#define WLAN_EID_FAST_BSS_TRANSITION 55 +#define WLAN_EID_TIMEOUT_INTERVAL 56 +#define WLAN_EID_RIC_DATA 57 +#define WLAN_EID_HT_OPERATION 61 +#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 +#define WLAN_EID_20_40_BSS_COEXISTENCE 72 +#define WLAN_EID_20_40_BSS_INTOLERANT 73 +#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 +#define WLAN_EID_MMIE 76 +#define WLAN_EID_VENDOR_SPECIFIC 221 + + +/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ +#define WLAN_ACTION_SPECTRUM_MGMT 0 +#define WLAN_ACTION_QOS 1 +#define WLAN_ACTION_DLS 2 +#define WLAN_ACTION_BLOCK_ACK 3 +#define WLAN_ACTION_PUBLIC 4 +#define WLAN_ACTION_RADIO_MEASUREMENT 5 +#define WLAN_ACTION_FT 6 +#define WLAN_ACTION_HT 7 +#define WLAN_ACTION_SA_QUERY 8 +#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ + +/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ +#define WLAN_SA_QUERY_REQUEST 0 +#define WLAN_SA_QUERY_RESPONSE 1 + +#define WLAN_SA_QUERY_TR_ID_LEN 2 + +/* Timeout Interval Type */ +#define WLAN_TIMEOUT_REASSOC_DEADLINE 1 +#define WLAN_TIMEOUT_KEY_LIFETIME 2 +#define WLAN_TIMEOUT_ASSOC_COMEBACK 3 + + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct ieee80211_hdr { + le16 frame_control; + le16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + le16 seq_ctrl; + /* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame + */ +} STRUCT_PACKED; + +#define IEEE80211_DA_FROMDS addr1 +#define IEEE80211_BSSID_FROMDS addr2 +#define IEEE80211_SA_FROMDS addr3 + +#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr)) + +#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) + +struct ieee80211_mgmt { + le16 frame_control; + le16 duration; + u8 da[6]; + u8 sa[6]; + u8 bssid[6]; + le16 seq_ctrl; + union { + struct { + le16 auth_alg; + le16 auth_transaction; + le16 status_code; + /* possibly followed by Challenge text */ + u8 variable[0]; + } STRUCT_PACKED auth; + struct { + le16 reason_code; + } STRUCT_PACKED deauth; + struct { + le16 capab_info; + le16 listen_interval; + /* followed by SSID and Supported rates */ + u8 variable[0]; + } STRUCT_PACKED assoc_req; + struct { + le16 capab_info; + le16 status_code; + le16 aid; + /* followed by Supported rates */ + u8 variable[0]; + } STRUCT_PACKED assoc_resp, reassoc_resp; + struct { + le16 capab_info; + le16 listen_interval; + u8 current_ap[6]; + /* followed by SSID and Supported rates */ + u8 variable[0]; + } STRUCT_PACKED reassoc_req; + struct { + le16 reason_code; + } STRUCT_PACKED disassoc; + struct { + u8 timestamp[8]; + le16 beacon_int; + le16 capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params, TIM */ + u8 variable[0]; + } STRUCT_PACKED beacon; + struct { + /* only variable items: SSID, Supported rates */ + u8 variable[0]; + } STRUCT_PACKED probe_req; + struct { + u8 timestamp[8]; + le16 beacon_int; + le16 capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params */ + u8 variable[0]; + } STRUCT_PACKED probe_resp; + struct { + u8 category; + union { + struct { + u8 action_code; + u8 dialog_token; + u8 status_code; + u8 variable[0]; + } STRUCT_PACKED wmm_action; + struct{ + u8 action_code; + u8 element_id; + u8 length; + u8 switch_mode; + u8 new_chan; + u8 switch_count; + } STRUCT_PACKED chan_switch; + struct { + u8 action; + u8 sta_addr[ETH_ALEN]; + u8 target_ap_addr[ETH_ALEN]; + u8 variable[0]; /* FT Request */ + } STRUCT_PACKED ft_action_req; + struct { + u8 action; + u8 sta_addr[ETH_ALEN]; + u8 target_ap_addr[ETH_ALEN]; + le16 status_code; + u8 variable[0]; /* FT Request */ + } STRUCT_PACKED ft_action_resp; + struct { + u8 action; + u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; + } STRUCT_PACKED sa_query_req; + struct { + u8 action; /* */ + u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; + } STRUCT_PACKED sa_query_resp; + } u; + } STRUCT_PACKED action; + } u; +} STRUCT_PACKED; + + +struct ieee80211_ht_capabilities { + le16 ht_capabilities_info; + u8 a_mpdu_params; + u8 supported_mcs_set[16]; + le16 ht_extended_capabilities; + le32 tx_bf_capability_info; + u8 asel_capabilities; +} STRUCT_PACKED; + + +struct ieee80211_ht_operation { + u8 control_chan; + u8 ht_param; + le16 operation_mode; + le16 stbc_param; + u8 basic_set[16]; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +#define ERP_INFO_NON_ERP_PRESENT BIT(0) +#define ERP_INFO_USE_PROTECTION BIT(1) +#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) + + +#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) +#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) +#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) +#define HT_CAP_INFO_SMPS_STATIC ((u16) 0) +#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) +#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) +#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) +#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) +#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) +#define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) +#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) +#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) +#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) +#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) +#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) +#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) +#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) +#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) +#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) +#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) + + +#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0)) +#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1 +#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8 +#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10)) +#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11)) + + +#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0)) +#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1)) +#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2)) +#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3)) +#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4)) +#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5)) +#define TX_BEAMFORM_CAP_CALIB_OFFSET 6 +#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8)) +#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9)) +#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10)) +#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11 +#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13 +#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15 +#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17 +#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19 +#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21 +#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23 +#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25 + + +#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0)) +#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1)) +#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2)) +#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3)) +#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4)) +#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5)) +#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6)) + +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) +#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) +#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) +#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) +#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) + + +#define OP_MODE_PURE 0 +#define OP_MODE_MAY_BE_LEGACY_STAS 1 +#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 +#define OP_MODE_MIXED 3 + +#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ + ((le16) (0x0001 | 0x0002)) +#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 +#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) +#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) +#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) + +#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) +#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) +#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) +#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) +#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) +#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) + + +#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) + * 00:50:F2 */ +#define WPA_IE_VENDOR_TYPE 0x0050f201 +#define WPS_IE_VENDOR_TYPE 0x0050f204 + +#define WMM_OUI_TYPE 2 +#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 +#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 +#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 +#define WMM_VERSION 1 + +#define WMM_ACTION_CODE_ADDTS_REQ 0 +#define WMM_ACTION_CODE_ADDTS_RESP 1 +#define WMM_ACTION_CODE_DELTS 2 + +#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0 +#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1 +/* 2 - Reserved */ +#define WMM_ADDTS_STATUS_REFUSED 3 +/* 4-255 - Reserved */ + +/* WMM TSPEC Direction Field Values */ +#define WMM_TSPEC_DIRECTION_UPLINK 0 +#define WMM_TSPEC_DIRECTION_DOWNLINK 1 +/* 2 - Reserved */ +#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 + +/* + * WMM Information Element (used in (Re)Association Request frames; may also be + * used in Beacon frames) + */ +struct wmm_information_element { + /* Element ID: 221 (0xdd); Length: 7 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 0 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specific QoS info */ + +} STRUCT_PACKED; + +#define WMM_AC_AIFSN_MASK 0x0f +#define WMM_AC_AIFNS_SHIFT 0 +#define WMM_AC_ACM 0x10 +#define WMM_AC_ACI_MASK 0x60 +#define WMM_AC_ACI_SHIFT 5 + +#define WMM_AC_ECWMIN_MASK 0x0f +#define WMM_AC_ECWMIN_SHIFT 0 +#define WMM_AC_ECWMAX_MASK 0xf0 +#define WMM_AC_ECWMAX_SHIFT 4 + +struct wmm_ac_parameter { + u8 aci_aifsn; /* AIFSN, ACM, ACI */ + u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ + le16 txop_limit; +} STRUCT_PACKED; + +/* + * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association + * Response frmaes) + */ +struct wmm_parameter_element { + /* Element ID: 221 (0xdd); Length: 24 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 1 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specif QoS info */ + u8 reserved; /* 0 */ + struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ + +} STRUCT_PACKED; + +/* WMM TSPEC Element */ +struct wmm_tspec_element { + u8 eid; /* 221 = 0xdd */ + u8 length; /* 6 + 55 = 61 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 2 */ + u8 version; /* 1 */ + /* WMM TSPEC body (55 octets): */ + u8 ts_info[3]; + le16 nominal_msdu_size; + le16 maximum_msdu_size; + le32 minimum_service_interval; + le32 maximum_service_interval; + le32 inactivity_interval; + le32 suspension_interval; + le32 service_start_time; + le32 minimum_data_rate; + le32 mean_data_rate; + le32 peak_data_rate; + le32 maximum_burst_size; + le32 delay_bound; + le32 minimum_phy_rate; + le16 surplus_bandwidth_allowance; + le16 medium_time; +} STRUCT_PACKED; + + +/* Access Categories / ACI to AC coding */ +enum { + WMM_AC_BE = 0 /* Best Effort */, + WMM_AC_BK = 1 /* Background */, + WMM_AC_VI = 2 /* Video */, + WMM_AC_VO = 3 /* Voice */ +}; + + +#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ + +#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ + +/* cipher suite selectors */ +#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 +#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 +#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 +/* reserved: 0x000FAC03 */ +#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 +#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 +#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 + +/* AKM suite selectors */ +#define WLAN_AKM_SUITE_8021X 0x000FAC01 +#define WLAN_AKM_SUITE_PSK 0x000FAC02 + +#endif /* IEEE802_11_DEFS_H */ diff --git a/components/wpa_supplicant/include/wpa/ieee802_1x.h b/components/wpa_supplicant/include/wpa/ieee802_1x.h new file mode 100644 index 0000000000..e10ff7b310 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/ieee802_1x.h @@ -0,0 +1,64 @@ +/* + * hostapd / IEEE 802.1X-2004 Authenticator + * Copyright (c) 2002-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef IEEE802_1X_H +#define IEEE802_1X_H + +struct hostapd_data; +struct sta_info; +struct eapol_state_machine; +struct hostapd_config; +struct hostapd_bss_config; +struct hostapd_radius_attr; +struct radius_msg; + + +void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, + size_t len); + +#if 0 +void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta); +void ieee802_1x_free_station(struct sta_info *sta); + +void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta); +void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta); +void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, + struct sta_info *sta, int authorized); +void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta); +int ieee802_1x_init(struct hostapd_data *hapd); +void ieee802_1x_deinit(struct hostapd_data *hapd); +int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *buf, size_t len, int ack); +int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, int len, int ack); +u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len); +u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, + int idx); +struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm); +const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len); +void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, + int enabled); +void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, + int valid); +void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth); +int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); +int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, + char *buf, size_t buflen); +void hostapd_get_ntp_timestamp(u8 *buf); +char *eap_type_text(u8 type); + +const char *radius_mode_txt(struct hostapd_data *hapd); +int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta); + +int add_common_radius_attr(struct hostapd_data *hapd, + struct hostapd_radius_attr *req_attr, + struct sta_info *sta, + struct radius_msg *msg); +#endif + +#endif /* IEEE802_1X_H */ diff --git a/components/wpa_supplicant/include/wpa/includes.h b/components/wpa_supplicant/include/wpa/includes.h new file mode 100644 index 0000000000..993bc49941 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/includes.h @@ -0,0 +1,31 @@ +/* + * wpa_supplicant/hostapd - Default include files + * Copyright (c) 2005-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This header file is included into all C files so that commonly used header + * files can be selected with OS specific ifdef blocks in one place instead of + * having to have OS/C library specific selection in many files. + */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +/* Include possible build time configuration before including anything else */ +//#include "build_config.h" //don't need anymore + +//#include +//#include +//#include +//#include +//#include + +#endif /* INCLUDES_H */ diff --git a/components/wpa_supplicant/include/wpa/list.h b/components/wpa_supplicant/include/wpa/list.h new file mode 100644 index 0000000000..c8dccee83d --- /dev/null +++ b/components/wpa_supplicant/include/wpa/list.h @@ -0,0 +1,101 @@ +/* + * Doubly-linked list + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef LIST_H +#define LIST_H + +/** + * struct dl_list - Doubly-linked list + */ +struct dl_list { + struct dl_list *next; + struct dl_list *prev; +}; + +static inline void dl_list_init(struct dl_list *list) +{ + list->next = list; + list->prev = list; +} + +static inline void dl_list_add(struct dl_list *list, struct dl_list *item) +{ + item->next = list->next; + item->prev = list; + list->next->prev = item; + list->next = item; +} + +static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item) +{ + dl_list_add(list->prev, item); +} + +static inline void dl_list_del(struct dl_list *item) +{ + item->next->prev = item->prev; + item->prev->next = item->next; + item->next = NULL; + item->prev = NULL; +} + +static inline int dl_list_empty(struct dl_list *list) +{ + return list->next == list; +} + +static inline unsigned int dl_list_len(struct dl_list *list) +{ + struct dl_list *item; + int count = 0; + for (item = list->next; item != list; item = item->next) + count++; + return count; +} + +#ifndef offsetof +#define offsetof(type, member) ((long) &((type *) 0)->member) +#endif + +#define dl_list_entry(item, type, member) \ + ((type *) ((char *) item - offsetof(type, member))) + +#define dl_list_first(list, type, member) \ + (dl_list_empty((list)) ? NULL : \ + dl_list_entry((list)->next, type, member)) + +#define dl_list_last(list, type, member) \ + (dl_list_empty((list)) ? NULL : \ + dl_list_entry((list)->prev, type, member)) + +#define dl_list_for_each(item, list, type, member) \ + for (item = dl_list_entry((list)->next, type, member); \ + &item->member != (list); \ + item = dl_list_entry(item->member.next, type, member)) + +#define dl_list_for_each_safe(item, n, list, type, member) \ + for (item = dl_list_entry((list)->next, type, member), \ + n = dl_list_entry(item->member.next, type, member); \ + &item->member != (list); \ + item = n, n = dl_list_entry(n->member.next, type, member)) + +#define dl_list_for_each_reverse(item, list, type, member) \ + for (item = dl_list_entry((list)->prev, type, member); \ + &item->member != (list); \ + item = dl_list_entry(item->member.prev, type, member)) + +#define DEFINE_DL_LIST(name) \ + struct dl_list name = { &(name), &(name) } + +#endif /* LIST_H */ diff --git a/components/wpa_supplicant/include/wpa/sta_info.h b/components/wpa_supplicant/include/wpa/sta_info.h new file mode 100644 index 0000000000..44874a2ff9 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/sta_info.h @@ -0,0 +1,194 @@ +/* + * hostapd / Station table + * Copyright (c) 2002-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef STA_INFO_H +#define STA_INFO_H + +/* STA flags */ +#define WLAN_STA_AUTH BIT(0) +#define WLAN_STA_ASSOC BIT(1) +#define WLAN_STA_PS BIT(2) +#define WLAN_STA_TIM BIT(3) +#define WLAN_STA_PERM BIT(4) +#define WLAN_STA_AUTHORIZED BIT(5) +#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ +#define WLAN_STA_SHORT_PREAMBLE BIT(7) +#define WLAN_STA_PREAUTH BIT(8) +#define WLAN_STA_WMM BIT(9) +#define WLAN_STA_MFP BIT(10) +#define WLAN_STA_HT BIT(11) +#define WLAN_STA_WPS BIT(12) +#define WLAN_STA_MAYBE_WPS BIT(13) +#define WLAN_STA_WDS BIT(14) +#define WLAN_STA_ASSOC_REQ_OK BIT(15) +#define WLAN_STA_WPS2 BIT(16) +#define WLAN_STA_GAS BIT(17) +#define WLAN_STA_VHT BIT(18) +#define WLAN_STA_PENDING_DISASSOC_CB BIT(29) +#define WLAN_STA_PENDING_DEAUTH_CB BIT(30) +#define WLAN_STA_NONERP BIT(31) + +/* Maximum number of supported rates (from both Supported Rates and Extended + * Supported Rates IEs). */ +#define WLAN_SUPP_RATES_MAX 32 + + +struct sta_info { + struct sta_info *next; /* next entry in sta list */ + struct sta_info *hnext; /* next entry in hash table list */ + u8 addr[6]; + u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ + u32 flags; /* Bitfield of WLAN_STA_* */ + u16 capability; + u16 listen_interval; /* or beacon_int for APs */ + u8 supported_rates[WLAN_SUPP_RATES_MAX]; + int supported_rates_len; +// u8 qosinfo; /* Valid when WLAN_STA_WMM is set */ + +// unsigned int nonerp_set:1; +// unsigned int no_short_slot_time_set:1; +// unsigned int no_short_preamble_set:1; +// unsigned int no_ht_gf_set:1; +// unsigned int no_ht_set:1; +// unsigned int ht_20mhz_set:1; +// unsigned int no_p2p_set:1; + + u16 auth_alg; +// u8 previous_ap[6]; + + enum { + STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE + } timeout_next; + +// u16 deauth_reason; +// u16 disassoc_reason; + + /* IEEE 802.1X related data */ +// struct eapol_state_machine *eapol_sm; + + /* IEEE 802.11f (IAPP) related data */ +// struct ieee80211_mgmt *last_assoc_req; + +// u32 acct_session_id_hi; +// u32 acct_session_id_lo; +// time_t acct_session_start; +// int acct_session_started; +// int acct_terminate_cause; /* Acct-Terminate-Cause */ +// int acct_interim_interval; /* Acct-Interim-Interval */ + +// unsigned long last_rx_bytes; +// unsigned long last_tx_bytes; +// u32 acct_input_gigawords; /* Acct-Input-Gigawords */ +// u32 acct_output_gigawords; /* Acct-Output-Gigawords */ + +// u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */ + + struct wpa_state_machine *wpa_sm; +// struct rsn_preauth_interface *preauth_iface; + + struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */ +// struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */ + +// int vlan_id; + /* PSKs from RADIUS authentication server */ +// struct hostapd_sta_wpa_psk_short *psk; + +// char *identity; /* User-Name from RADIUS */ +// char *radius_cui; /* Chargeable-User-Identity from RADIUS */ + +// struct ieee80211_ht_capabilities *ht_capabilities; +// struct ieee80211_vht_capabilities *vht_capabilities; + +#ifdef CONFIG_IEEE80211W + int sa_query_count; /* number of pending SA Query requests; + * 0 = no SA Query in progress */ + int sa_query_timed_out; + u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN * + * sa_query_count octets of pending SA Query + * transaction identifiers */ + struct os_time sa_query_start; +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_INTERWORKING +#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */ + struct gas_dialog_info *gas_dialog; + u8 gas_dialog_next; +#endif /* CONFIG_INTERWORKING */ + +// struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */ +// struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */ +// struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */ + +// struct os_time connected_time; + +#ifdef CONFIG_SAE + enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state; + u16 sae_send_confirm; +#endif /* CONFIG_SAE */ +}; + + +/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has + * passed since last received frame from the station, a nullfunc data frame is + * sent to the station. If this frame is not acknowledged and no other frames + * have been received, the station will be disassociated after + * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated + * after AP_DEAUTH_DELAY seconds has passed after disassociation. */ +#define AP_MAX_INACTIVITY (5 * 60) +#define AP_DISASSOC_DELAY (1) +#define AP_DEAUTH_DELAY (1) +/* Number of seconds to keep STA entry with Authenticated flag after it has + * been disassociated. */ +#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30) +/* Number of seconds to keep STA entry after it has been deauthenticated. */ +#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5) + + +struct hostapd_data; + +int ap_for_each_sta(struct hostapd_data *hapd, + int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, + void *ctx), + void *ctx); +struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta); +void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta); +void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta); +void hostapd_free_stas(struct hostapd_data *hapd); +void ap_handle_timer(void *eloop_ctx, void *timeout_ctx); +void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, + u32 session_timeout); +void ap_sta_no_session_timeout(struct hostapd_data *hapd, + struct sta_info *sta); +struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr); +void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, + u16 reason); +void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, + u16 reason); +#ifdef CONFIG_WPS +int ap_sta_wps_cancel(struct hostapd_data *hapd, + struct sta_info *sta, void *ctx); +#endif /* CONFIG_WPS */ +int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, + int old_vlanid); +void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta); +int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *addr, u16 reason); + +void ap_sta_set_authorized(struct hostapd_data *hapd, + struct sta_info *sta, int authorized); +static inline int ap_sta_is_authorized(struct sta_info *sta) +{ + return sta->flags & WLAN_STA_AUTHORIZED; +} + +void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta); + +#endif /* STA_INFO_H */ diff --git a/components/wpa_supplicant/include/wpa/state_machine.h b/components/wpa_supplicant/include/wpa/state_machine.h new file mode 100644 index 0000000000..ce8c51e770 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/state_machine.h @@ -0,0 +1,138 @@ +/* + * wpa_supplicant/hostapd - State machine definitions + * Copyright (c) 2002-2005, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + * + * This file includes a set of pre-processor macros that can be used to + * implement a state machine. In addition to including this header file, each + * file implementing a state machine must define STATE_MACHINE_DATA to be the + * data structure including state variables (enum machine_state, + * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used + * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define + * a group of state machines with shared data structure, STATE_MACHINE_ADDR + * needs to be defined to point to the MAC address used in debug output. + * SM_ENTRY_M macro can be used to define similar group of state machines + * without this additional debug info. + */ + +#ifndef STATE_MACHINE_H +#define STATE_MACHINE_H + +/** + * SM_STATE - Declaration of a state machine function + * @machine: State machine name + * @state: State machine state + * + * This macro is used to declare a state machine function. It is used in place + * of a C function definition to declare functions to be run when the state is + * entered by calling SM_ENTER or SM_ENTER_GLOBAL. + */ +#define SM_STATE(machine, state) \ +static void ICACHE_FLASH_ATTR sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \ + int global) + +/** + * SM_ENTRY - State machine function entry point + * @machine: State machine name + * @state: State machine state + * + * This macro is used inside each state machine function declared with + * SM_STATE. SM_ENTRY should be in the beginning of the function body, but + * after declaration of possible local variables. This macro prints debug + * information about state transition and update the state machine state. + */ +#define SM_ENTRY(machine, state) \ +if (!global || sm->machine ## _state != machine ## _ ## state) { \ + sm->changed = TRUE; \ + wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \ + " entering state " #state); \ +} \ +sm->machine ## _state = machine ## _ ## state; + +/** + * SM_ENTRY_M - State machine function entry point for state machine group + * @machine: State machine name + * @_state: State machine state + * @data: State variable prefix (full variable: prefix_state) + * + * This macro is like SM_ENTRY, but for state machine groups that use a shared + * data structure for more than one state machine. Both machine and prefix + * parameters are set to "sub-state machine" name. prefix is used to allow more + * than one state variable to be stored in the same data structure. + */ +#define SM_ENTRY_M(machine, _state, data) \ +if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ + sm->changed = TRUE; \ + wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \ + #machine " entering state " #_state); \ +} \ +sm->data ## _ ## state = machine ## _ ## _state; + +/** + * SM_ENTRY_MA - State machine function entry point for state machine group + * @machine: State machine name + * @_state: State machine state + * @data: State variable prefix (full variable: prefix_state) + * + * This macro is like SM_ENTRY_M, but a MAC address is included in debug + * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to + * be included in debug. + */ +#define SM_ENTRY_MA(machine, _state, data) \ +if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ + sm->changed = TRUE; \ + wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \ + #machine " entering state " #_state"\n", \ + MAC2STR(STATE_MACHINE_ADDR)); \ +} \ +sm->data ## _ ## state = machine ## _ ## _state; + +/** + * SM_ENTER - Enter a new state machine state + * @machine: State machine name + * @state: State machine state + * + * This macro expands to a function call to a state machine function defined + * with SM_STATE macro. SM_ENTER is used in a state machine step function to + * move the state machine to a new state. + */ +#define SM_ENTER(machine, state) \ +sm_ ## machine ## _ ## state ## _Enter(sm, 0) + +/** + * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule + * @machine: State machine name + * @state: State machine state + * + * This macro is like SM_ENTER, but this is used when entering a new state + * based on a global (not specific to any particular state) rule. A separate + * macro is used to avoid unwanted debug message floods when the same global + * rule is forcing a state machine to remain in on state. + */ +#define SM_ENTER_GLOBAL(machine, state) \ +sm_ ## machine ## _ ## state ## _Enter(sm, 1) + +/** + * SM_STEP - Declaration of a state machine step function + * @machine: State machine name + * + * This macro is used to declare a state machine step function. It is used in + * place of a C function definition to declare a function that is used to move + * state machine to a new state based on state variables. This function uses + * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state. + */ +#define SM_STEP(machine) \ +static void ICACHE_FLASH_ATTR sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm) + +/** + * SM_STEP_RUN - Call the state machine step function + * @machine: State machine name + * + * This macro expands to a function call to a state machine step function + * defined with SM_STEP macro. + */ +#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm) + +#endif /* STATE_MACHINE_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa.h b/components/wpa_supplicant/include/wpa/wpa.h new file mode 100644 index 0000000000..2a1adfc567 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa.h @@ -0,0 +1,193 @@ +/* + * wpa_supplicant - WPA definitions + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_H +#define WPA_H + +#include "c_types.h" +#include "os_type.h" +#include "common.h" +#include "ets_sys.h" +#include "wpa/defs.h" +#include "wpa/wpa_common.h" + +//#include "net80211/ieee80211_var.h" +//#include "net80211/ieee80211_node.h" + +#define WPA_SM_STATE(_sm) ((_sm)->wpa_state) + +struct wpa_sm; + +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); + +#define WPA_ASSERT ASSERT + +struct install_key { + int mic_errors_seen; /* Michael MIC errors with the current PTK */ + int keys_cleared; + enum wpa_alg alg; + u8 addr[ETH_ALEN]; + int key_idx; + int set_tx; + u8 seq[10]; + u8 key[32]; +}; + +/** + * struct wpa_sm - Internal WPA state machine data + */ +struct wpa_sm { + u8 pmk[PMK_LEN]; + size_t pmk_len; + +// char *passphrase; //wlan password +// u8 *ssid; //wlan network name +// size_t ssid_len; + + struct wpa_ptk ptk, tptk; + int ptk_set, tptk_set; + u8 snonce[WPA_NONCE_LEN]; + u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */ + int renew_snonce; + u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; + int rx_replay_counter_set; + u8 request_counter[WPA_REPLAY_COUNTER_LEN]; + +// void *network_ctx; + + unsigned int pairwise_cipher; + unsigned int group_cipher; + unsigned int key_mgmt; + unsigned int mgmt_group_cipher; + + int rsn_enabled; /* Whether RSN is enabled in configuration */ + + int countermeasures; /*TKIP countermeasures state flag, 1:in countermeasures state*/ + os_timer_t cm_timer; + + u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ + size_t assoc_wpa_ie_len; + + u8 eapol_version; + + int wpa_ptk_rekey; + u8 own_addr[ETH_ALEN]; + + u8 bssid[ETH_ALEN]; + + unsigned int proto; + enum wpa_states wpa_state; + + u8 *ap_wpa_ie, *ap_rsn_ie; + size_t ap_wpa_ie_len, ap_rsn_ie_len; + + struct install_key install_ptk; + struct install_key install_gtk; + int key_entry_valid; //present current avaliable entry for bssid, for pairkey:0,5,10,15,20, gtk: pairkey_no+i (i:1~4) + +// char *msg; //send eapol msg buff +// size_t msg_len; //msg length:6 + sizeof(eth) + data_len + +// struct netif *ifp; + struct pbuf *pb; + + void (* sendto) (struct pbuf *pb); + void (*config_assoc_ie) (uint8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); + void (*install_ppkey) (enum wpa_alg alg, uint8 *addr, int key_idx, int set_tx, + uint8 *seq, size_t seq_len, uint8 *key, size_t key_len, int key_entry_valid); + void (*wpa_deauthenticate)(uint8 reason_code); + void (*wpa_neg_complete)(); + struct wpa_gtk_data gd; //used for calllback save param + uint16 key_info; //used for txcallback param +}; + +struct l2_ethhdr { + u8 h_dest[ETH_ALEN]; + u8 h_source[ETH_ALEN]; + be16 h_proto; +} STRUCT_PACKED; + +/** + * set_key - Configure encryption key + * @ifname: Interface name (for multi-SSID/VLAN support) + * @priv: private driver interface data + * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, + * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK); + * %WPA_ALG_NONE clears the key. + * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for + * broadcast/default keys + * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for + * IGTK + * @set_tx: configure this key as the default Tx key (only used when + * driver does not support separate unicast/individual key + * @seq: sequence number/packet number, seq_len octets, the next + * packet number to be used for in replay protection; configured + * for Rx keys (in most cases, this is only used with broadcast + * keys and set to zero for unicast keys) + * @seq_len: length of the seq, depends on the algorithm: + * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets + * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, + * 8-byte Rx Mic Key + * @key_len: length of the key buffer in octets (WEP: 5 or 13, + * TKIP: 32, CCMP: 16, IGTK: 16) + * + * Returns: 0 on success, -1 on failure + * + * Configure the given key for the kernel driver. If the driver + * supports separate individual keys (4 default keys + 1 individual), + * addr can be used to determine whether the key is default or + * individual. If only 4 keys are supported, the default key with key + * index 0 is used as the individual key. STA must be configured to use + * it as the default Tx key (set_tx is set) and accept Rx for all the + * key indexes. In most cases, WPA uses only key indexes 1 and 2 for + * broadcast keys, so key index 0 is available for this kind of + * configuration. + * + * Please note that TKIP keys include separate TX and RX MIC keys and + * some drivers may expect them in different order than wpa_supplicant + * is using. If the TX/RX keys are swapped, all TKIP encrypted packets + * will tricker Michael MIC errors. This can be fixed by changing the + * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key + * in driver_*.c set_key() implementation, see driver_ndis.c for an + * example on how this can be done. + */ + + +/** + * send_eapol - Optional function for sending EAPOL packets + * @priv: private driver interface data + * @dest: Destination MAC address + * @proto: Ethertype + * @data: EAPOL packet starting with IEEE 802.1X header + * @data_len: Size of the EAPOL packet + * + * Returns: 0 on success, -1 on failure + * + * This optional function can be used to override l2_packet operations + * with driver specific functionality. If this function pointer is set, + * l2_packet module is not used at all and the driver interface code is + * responsible for receiving and sending all EAPOL packets. The + * received EAPOL packets are sent to core code with EVENT_EAPOL_RX + * event. The driver interface is required to implement get_mac_addr() + * handler if send_eapol() is used. + */ + +#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5) + +void pp_michael_mic_failure(uint16 isunicast); + +void wpa_sm_set_state(enum wpa_states state); + +#endif /* WPA_H */ + diff --git a/components/wpa_supplicant/include/wpa/wpa_auth.h b/components/wpa_supplicant/include/wpa/wpa_auth.h new file mode 100644 index 0000000000..c729923494 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_auth.h @@ -0,0 +1,292 @@ +/* + * hostapd - IEEE 802.11i-2004 / WPA Authenticator + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_AUTH_H +#define WPA_AUTH_H + +#include "wpa/defs.h" +#include "wpa/eapol_common.h" +#include "wpa/wpa_common.h" + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition + */ +struct ft_rrb_frame { + u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ + u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */ + le16 action_length; /* little endian length of action_frame */ + u8 ap_address[ETH_ALEN]; + /* + * Followed by action_length bytes of FT Action frame (from Category + * field to the end of Action Frame body. + */ +} STRUCT_PACKED; + +#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1 + +#define FT_PACKET_REQUEST 0 +#define FT_PACKET_RESPONSE 1 +/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */ +#define FT_PACKET_R0KH_R1KH_PULL 200 +#define FT_PACKET_R0KH_R1KH_RESP 201 +#define FT_PACKET_R0KH_R1KH_PUSH 202 + +#define FT_R0KH_R1KH_PULL_DATA_LEN 44 +#define FT_R0KH_R1KH_RESP_DATA_LEN 76 +#define FT_R0KH_R1KH_PUSH_DATA_LEN 88 + +struct ft_r0kh_r1kh_pull_frame { + u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ + u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */ + le16 data_length; /* little endian length of data (44) */ + u8 ap_address[ETH_ALEN]; + + u8 nonce[16]; + u8 pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 r1kh_id[FT_R1KH_ID_LEN]; + u8 s1kh_id[ETH_ALEN]; + u8 pad[4]; /* 8-octet boundary for AES key wrap */ + u8 key_wrap_extra[8]; +} STRUCT_PACKED; + +struct ft_r0kh_r1kh_resp_frame { + u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ + u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */ + le16 data_length; /* little endian length of data (76) */ + u8 ap_address[ETH_ALEN]; + + u8 nonce[16]; /* copied from pull */ + u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */ + u8 s1kh_id[ETH_ALEN]; /* copied from pull */ + u8 pmk_r1[PMK_LEN]; + u8 pmk_r1_name[WPA_PMK_NAME_LEN]; + le16 pairwise; + u8 pad[2]; /* 8-octet boundary for AES key wrap */ + u8 key_wrap_extra[8]; +} STRUCT_PACKED; + +struct ft_r0kh_r1kh_push_frame { + u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ + u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */ + le16 data_length; /* little endian length of data (88) */ + u8 ap_address[ETH_ALEN]; + + /* Encrypted with AES key-wrap */ + u8 timestamp[4]; /* current time in seconds since unix epoch, little + * endian */ + u8 r1kh_id[FT_R1KH_ID_LEN]; + u8 s1kh_id[ETH_ALEN]; + u8 pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 pmk_r1[PMK_LEN]; + u8 pmk_r1_name[WPA_PMK_NAME_LEN]; + le16 pairwise; + u8 pad[6]; /* 8-octet boundary for AES key wrap */ + u8 key_wrap_extra[8]; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +/* per STA state machine data */ + +struct wpa_authenticator; +struct wpa_state_machine; +struct rsn_pmksa_cache_entry; +struct eapol_state_machine; + + +struct ft_remote_r0kh { + struct ft_remote_r0kh *next; + u8 addr[ETH_ALEN]; + u8 id[FT_R0KH_ID_MAX_LEN]; + size_t id_len; + u8 key[16]; +}; + + +struct ft_remote_r1kh { + struct ft_remote_r1kh *next; + u8 addr[ETH_ALEN]; + u8 id[FT_R1KH_ID_LEN]; + u8 key[16]; +}; + + +struct wpa_auth_config { + int wpa; + int wpa_key_mgmt; + int wpa_pairwise; + int wpa_group; + int wpa_group_rekey; + int wpa_strict_rekey; + int wpa_gmk_rekey; + int wpa_ptk_rekey; + int rsn_pairwise; + int rsn_preauth; + int eapol_version; + int peerkey; + int wmm_enabled; + int wmm_uapsd; + int disable_pmksa_caching; + int okc; + int tx_status; +#ifdef CONFIG_IEEE80211W + enum mfp_options ieee80211w; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R +#define SSID_LEN 32 + u8 ssid[SSID_LEN]; + size_t ssid_len; + u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; + u8 r0_key_holder[FT_R0KH_ID_MAX_LEN]; + size_t r0_key_holder_len; + u8 r1_key_holder[FT_R1KH_ID_LEN]; + u32 r0_key_lifetime; + u32 reassociation_deadline; + struct ft_remote_r0kh *r0kh_list; + struct ft_remote_r1kh *r1kh_list; + int pmk_r1_push; + int ft_over_ds; +#endif /* CONFIG_IEEE80211R */ + int disable_gtk; + int ap_mlme; +}; + +typedef enum { + LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING +} logger_level; + +typedef enum { + WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized, + WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable, + WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx +} wpa_eapol_variable; + +struct wpa_auth_callbacks { + void *ctx; + void (*logger)(void *ctx, const u8 *addr, logger_level level, + const char *txt); + void (*disconnect)(void *ctx, const u8 *addr, u16 reason); + int (*mic_failure_report)(void *ctx, const u8 *addr); + void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var, + int value); + int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var); + const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk); + int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len); + int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg, + const u8 *addr, int idx, u8 *key, size_t key_len); + int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq); + int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data, + size_t data_len, int encrypt); + int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm, + void *ctx), void *cb_ctx); + int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a, + void *ctx), void *cb_ctx); + int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data, + size_t data_len); +#ifdef CONFIG_IEEE80211R + struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); + int (*send_ft_action)(void *ctx, const u8 *dst, + const u8 *data, size_t data_len); + int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie, + size_t tspec_ielen); +#endif /* CONFIG_IEEE80211R */ +}; + +struct wpa_authenticator * wpa_init(const u8 *addr, + struct wpa_auth_config *conf, + struct wpa_auth_callbacks *cb); +int wpa_init_keys(struct wpa_authenticator *wpa_auth); +void wpa_deinit(struct wpa_authenticator *wpa_auth); +int wpa_reconfig(struct wpa_authenticator *wpa_auth, + struct wpa_auth_config *conf); + +enum { + WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE, + WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL, + WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER, + WPA_INVALID_MDIE, WPA_INVALID_PROTO +}; + +int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + const u8 *wpa_ie, size_t wpa_ie_len/*, + const u8 *mdie, size_t mdie_len*/); +int wpa_auth_uses_mfp(struct wpa_state_machine *sm); +struct wpa_state_machine * +wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr); +int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm); +void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm); +void wpa_auth_sta_deinit(struct wpa_state_machine *sm); +void wpa_receive(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + u8 *data, size_t data_len); +typedef enum { + WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, + WPA_REAUTH_EAPOL, WPA_ASSOC_FT +} wpa_event; +void wpa_remove_ptk(struct wpa_state_machine *sm); +int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event); +void wpa_auth_sm_notify(struct wpa_state_machine *sm); +void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth); +int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen); +int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen); +void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth); +int wpa_auth_pairwise_set(struct wpa_state_machine *sm); +int wpa_auth_get_pairwise(struct wpa_state_machine *sm); +int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm); +int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm); +int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, + struct rsn_pmksa_cache_entry *entry); +struct rsn_pmksa_cache_entry * +wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm); +void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm); +const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, + size_t *len); +int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, + int session_timeout, struct eapol_state_machine *eapol); +int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, + const u8 *pmk, size_t len, const u8 *sta_addr, + int session_timeout, + struct eapol_state_machine *eapol); +int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id); +void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int ack); + +#ifdef CONFIG_IEEE80211R +u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, + size_t max_len, int auth_alg, + const u8 *req_ies, size_t req_ies_len); +void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, + u16 auth_transaction, const u8 *ies, size_t ies_len, + void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, + u16 auth_transaction, u16 resp, + const u8 *ies, size_t ies_len), + void *ctx); +u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, + size_t ies_len); +int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len); +int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, + const u8 *data, size_t data_len); +void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr); +#endif /* CONFIG_IEEE80211R */ + +void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm); +void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag); +int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos); +int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos); + +int wpa_auth_uses_sae(struct wpa_state_machine *sm); + +#endif /* WPA_AUTH_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_auth_i.h b/components/wpa_supplicant/include/wpa/wpa_auth_i.h new file mode 100644 index 0000000000..53ad8ea941 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_auth_i.h @@ -0,0 +1,234 @@ +/* + * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_AUTH_I_H +#define WPA_AUTH_I_H + +/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */ +#define RSNA_MAX_EAPOL_RETRIES 4 + +struct wpa_group; + +struct wpa_stsl_negotiation { + struct wpa_stsl_negotiation *next; + u8 initiator[ETH_ALEN]; + u8 peer[ETH_ALEN]; +}; + + +struct wpa_state_machine { + struct wpa_authenticator *wpa_auth; + struct wpa_group *group; + + u8 addr[ETH_ALEN]; + + enum { + WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED, + WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2, + WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART, + WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2, + WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE + } wpa_ptk_state; + + enum { + WPA_PTK_GROUP_IDLE = 0, + WPA_PTK_GROUP_REKEYNEGOTIATING, + WPA_PTK_GROUP_REKEYESTABLISHED, + WPA_PTK_GROUP_KEYERROR + } wpa_ptk_group_state; + + Boolean Init; + Boolean DeauthenticationRequest; + Boolean AuthenticationRequest; + Boolean ReAuthenticationRequest; + Boolean Disconnect; + int TimeoutCtr; + int GTimeoutCtr; + Boolean TimeoutEvt; + Boolean EAPOLKeyReceived; + Boolean EAPOLKeyPairwise; + Boolean EAPOLKeyRequest; + Boolean MICVerified; + Boolean GUpdateStationKeys; + u8 ANonce[WPA_NONCE_LEN]; + u8 SNonce[WPA_NONCE_LEN]; + u8 PMK[PMK_LEN]; + struct wpa_ptk PTK; + Boolean PTK_valid; + Boolean pairwise_set; + int keycount; + Boolean Pair; + struct wpa_key_replay_counter { + u8 counter[WPA_REPLAY_COUNTER_LEN]; + Boolean valid; + } key_replay[RSNA_MAX_EAPOL_RETRIES], + prev_key_replay[RSNA_MAX_EAPOL_RETRIES]; + Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */ + Boolean PTKRequest; /* not in IEEE 802.11i state machine */ + Boolean has_GTK; + Boolean PtkGroupInit; /* init request for PTK Group state machine */ + + u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */ + size_t last_rx_eapol_key_len; + + unsigned int changed:1; + unsigned int in_step_loop:1; + unsigned int pending_deinit:1; + unsigned int started:1; + unsigned int mgmt_frame_prot:1; + unsigned int rx_eapol_key_secure:1; + unsigned int update_snonce:1; +#ifdef CONFIG_IEEE80211R + unsigned int ft_completed:1; + unsigned int pmk_r1_name_valid:1; +#endif /* CONFIG_IEEE80211R */ + unsigned int is_wnmsleep:1; + + u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN]; + int req_replay_counter_used; + + u8 *wpa_ie; + size_t wpa_ie_len; + + enum { + WPA_VERSION_NO_WPA = 0 /* WPA not used */, + WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */, + WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */ + } wpa; + int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ + int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */ +// struct rsn_pmksa_cache_entry *pmksa; + +// u32 dot11RSNAStatsTKIPLocalMICFailures; +// u32 dot11RSNAStatsTKIPRemoteMICFailures; + +#ifdef CONFIG_IEEE80211R + u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ + size_t xxkey_len; + u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth + * Request */ + u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */ + size_t r0kh_id_len; + u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key + * message 2/4 */ + u8 *assoc_resp_ftie; +#endif /* CONFIG_IEEE80211R */ + + int pending_1_of_4_timeout; +}; + + +/* per group key state machine data */ +struct wpa_group { + struct wpa_group *next; + int vlan_id; + + Boolean GInit; + int GKeyDoneStations; + Boolean GTKReKey; + int GTK_len; + int GN, GM; + Boolean GTKAuthenticator; + u8 Counter[WPA_NONCE_LEN]; + + enum { + WPA_GROUP_GTK_INIT = 0, + WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE + } wpa_group_state; + + u8 GMK[WPA_GMK_LEN]; + u8 GTK[2][WPA_GTK_MAX_LEN]; + u8 GNonce[WPA_NONCE_LEN]; + Boolean changed; + Boolean first_sta_seen; + Boolean reject_4way_hs_for_entropy; +#ifdef CONFIG_IEEE80211W + u8 IGTK[2][WPA_IGTK_LEN]; + int GN_igtk, GM_igtk; +#endif /* CONFIG_IEEE80211W */ +}; + + +struct wpa_ft_pmk_cache; + +/* per authenticator data */ +struct wpa_authenticator { + struct wpa_group *group; + +// unsigned int dot11RSNAStatsTKIPRemoteMICFailures; +// u32 dot11RSNAAuthenticationSuiteSelected; +// u32 dot11RSNAPairwiseCipherSelected; +// u32 dot11RSNAGroupCipherSelected; +// u8 dot11RSNAPMKIDUsed[PMKID_LEN]; +// u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */ +// u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */ +// u32 dot11RSNAGroupCipherRequested; /* FIX: update */ +// unsigned int dot11RSNATKIPCounterMeasuresInvoked; +// unsigned int dot11RSNA4WayHandshakeFailures; + +// struct wpa_stsl_negotiation *stsl_negotiations; + + struct wpa_auth_config conf; +// struct wpa_auth_callbacks cb; + + u8 *wpa_ie; + size_t wpa_ie_len; + + u8 addr[ETH_ALEN]; + +// struct rsn_pmksa_cache *pmksa; +// struct wpa_ft_pmk_cache *ft_pmk_cache; +}; + + +int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, + const u8 *pmkid); +#if 0 +void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, + logger_level level, const char *txt); +void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, + logger_level level, const char *fmt, ...); +#endif +void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int key_info, + const u8 *key_rsc, const u8 *nonce, + const u8 *kde, size_t kde_len, + int keyidx, int encr, int force_version); +int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, + int (*cb)(struct wpa_state_machine *sm, void *ctx), + void *cb_ctx); +int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, + int (*cb)(struct wpa_authenticator *a, void *ctx), + void *cb_ctx); + +#ifdef CONFIG_PEERKEY +int wpa_stsl_remove(struct wpa_authenticator *wpa_auth, + struct wpa_stsl_negotiation *neg); +void wpa_smk_error(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, struct wpa_eapol_key *key); +void wpa_smk_m1(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, struct wpa_eapol_key *key); +void wpa_smk_m3(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, struct wpa_eapol_key *key); +#endif /* CONFIG_PEERKEY */ + +#ifdef CONFIG_IEEE80211R +int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); +int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id, + size_t r0kh_id_len, + const u8 *anonce, const u8 *snonce, + u8 *buf, size_t len, const u8 *subelem, + size_t subelem_len); +int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, + struct wpa_ptk *ptk, size_t ptk_len); +struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); +void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); +void wpa_ft_install_ptk(struct wpa_state_machine *sm); +#endif /* CONFIG_IEEE80211R */ + +#endif /* WPA_AUTH_I_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_auth_ie.h b/components/wpa_supplicant/include/wpa/wpa_auth_ie.h new file mode 100644 index 0000000000..4999139510 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_auth_ie.h @@ -0,0 +1,50 @@ +/* + * hostapd - WPA/RSN IE and KDE definitions + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_AUTH_IE_H +#define WPA_AUTH_IE_H + +struct wpa_eapol_ie_parse { + const u8 *wpa_ie; + size_t wpa_ie_len; + const u8 *rsn_ie; + size_t rsn_ie_len; + const u8 *pmkid; + const u8 *gtk; + size_t gtk_len; + const u8 *mac_addr; + size_t mac_addr_len; +#ifdef CONFIG_PEERKEY + const u8 *smk; + size_t smk_len; + const u8 *nonce; + size_t nonce_len; + const u8 *lifetime; + size_t lifetime_len; + const u8 *error; + size_t error_len; +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211W + const u8 *igtk; + size_t igtk_len; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R + const u8 *mdie; + size_t mdie_len; + const u8 *ftie; + size_t ftie_len; +#endif /* CONFIG_IEEE80211R */ +}; + +int wpa_parse_kde_ies(const u8 *buf, size_t len, + struct wpa_eapol_ie_parse *ie); +u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, + const u8 *data2, size_t data2_len); +int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth); + +#endif /* WPA_AUTH_IE_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_common.h b/components/wpa_supplicant/include/wpa/wpa_common.h new file mode 100644 index 0000000000..480cf0e27e --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_common.h @@ -0,0 +1,332 @@ +/* + * WPA definitions shared between hostapd and wpa_supplicant + * Copyright (c) 2002-2008, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "os.h" +#ifndef WPA_COMMON_H +#define WPA_COMMON_H + +#define WPA_MAX_SSID_LEN 32 + +/* IEEE 802.11i */ +#define PMKID_LEN 16 +#define PMK_LEN 32 +#define WPA_REPLAY_COUNTER_LEN 8 +#define WPA_NONCE_LEN 32 +#define WPA_KEY_RSC_LEN 8 +#define WPA_GMK_LEN 32 +#define WPA_GTK_MAX_LEN 32 + +#define WPA_SELECTOR_LEN 4 +#define WPA_VERSION 1 +#define RSN_SELECTOR_LEN 4 +#define RSN_VERSION 1 + +#define RSN_SELECTOR(a, b, c, d) \ + ((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \ + (u32) (d)) + +#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) +#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1) +#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2) +#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) +#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1) +#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2) +#if 0 +#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3) +#endif +#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4) +#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5) + + +#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1) +#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2) +#ifdef CONFIG_IEEE80211R +#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3) +#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4) +#endif /* CONFIG_IEEE80211R */ +#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) +#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6) + +#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) +#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) +#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2) +#if 0 +#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3) +#endif +#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) +#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) +#ifdef CONFIG_IEEE80211W +#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6) +#endif /* CONFIG_IEEE80211W */ +#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) +#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8) + +/* EAPOL-Key Key Data Encapsulation + * GroupKey and PeerKey require encryption, otherwise, encryption is optional. + */ +#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1) +#if 0 +#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2) +#endif +#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3) +#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4) +#ifdef CONFIG_PEERKEY +#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5) +#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6) +#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7) +#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8) +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211W +#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9) +#endif /* CONFIG_IEEE80211W */ + +#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1) + +#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val)) +#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a)) + +#define RSN_NUM_REPLAY_COUNTERS_1 0 +#define RSN_NUM_REPLAY_COUNTERS_2 1 +#define RSN_NUM_REPLAY_COUNTERS_4 2 +#define RSN_NUM_REPLAY_COUNTERS_16 3 + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +#ifdef CONFIG_IEEE80211W +#define WPA_IGTK_LEN 16 +#endif /* CONFIG_IEEE80211W */ + + +/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */ +#define WPA_CAPABILITY_PREAUTH BIT(0) +#define WPA_CAPABILITY_NO_PAIRWISE BIT(1) +/* B2-B3: PTKSA Replay Counter */ +/* B4-B5: GTKSA Replay Counter */ +#define WPA_CAPABILITY_MFPR BIT(6) +#define WPA_CAPABILITY_MFPC BIT(7) +#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) + + +/* IEEE 802.11r */ +#define MOBILITY_DOMAIN_ID_LEN 2 +#define FT_R0KH_ID_MAX_LEN 48 +#define FT_R1KH_ID_LEN 6 +#define WPA_PMK_NAME_LEN 16 + + +/* IEEE 802.11, 8.5.2 EAPOL-Key frames */ +#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) +#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) +#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) +#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3 +#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ +/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ +#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5)) +#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 +#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */ +#define WPA_KEY_INFO_TXRX BIT(6) /* group */ +#define WPA_KEY_INFO_ACK BIT(7) +#define WPA_KEY_INFO_MIC BIT(8) +#define WPA_KEY_INFO_SECURE BIT(9) +#define WPA_KEY_INFO_ERROR BIT(10) +#define WPA_KEY_INFO_REQUEST BIT(11) +#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */ +#define WPA_KEY_INFO_SMK_MESSAGE BIT(13) + + +struct wpa_eapol_key { + u8 type; + /* Note: key_info, key_length, and key_data_length are unaligned */ + u8 key_info[2]; /* big endian */ + u8 key_length[2]; /* big endian */ + u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; + u8 key_nonce[WPA_NONCE_LEN]; + u8 key_iv[16]; + u8 key_rsc[WPA_KEY_RSC_LEN]; + u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */ + u8 key_mic[16]; + u8 key_data_length[2]; /* big endian */ + /* followed by key_data_length bytes of key_data */ +} STRUCT_PACKED; + +/** + * struct wpa_ptk - WPA Pairwise Transient Key + * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy + */ +struct wpa_ptk { + u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */ + u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */ + u8 tk1[16]; /* Temporal Key 1 (TK1) */ + union { + u8 tk2[16]; /* Temporal Key 2 (TK2) */ + struct { + u8 tx_mic_key[8]; + u8 rx_mic_key[8]; + } auth; + } u; +} STRUCT_PACKED; + +struct wpa_gtk_data { + enum wpa_alg alg; + int tx, key_rsc_len, keyidx; + u8 gtk[32]; + int gtk_len; +}; + + +/* WPA IE version 1 + * 00-50-f2:1 (OUI:OUI type) + * 0x01 0x00 (version; little endian) + * (all following fields are optional:) + * Group Suite Selector (4 octets) (default: TKIP) + * Pairwise Suite Count (2 octets, little endian) (default: 1) + * Pairwise Suite List (4 * n octets) (default: TKIP) + * Authenticated Key Management Suite Count (2 octets, little endian) + * (default: 1) + * Authenticated Key Management Suite List (4 * n octets) + * (default: unspec 802.1X) + * WPA Capabilities (2 octets, little endian) (default: 0) + */ + +struct wpa_ie_hdr { + u8 elem_id; + u8 len; + u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ + u8 version[2]; /* little endian */ +} STRUCT_PACKED; + + +/* 1/4: PMKID + * 2/4: RSN IE + * 3/4: one or two RSN IEs + GTK IE (encrypted) + * 4/4: empty + * 1/2: GTK IE (encrypted) + * 2/2: empty + */ + +/* RSN IE version 1 + * 0x01 0x00 (version; little endian) + * (all following fields are optional:) + * Group Suite Selector (4 octets) (default: CCMP) + * Pairwise Suite Count (2 octets, little endian) (default: 1) + * Pairwise Suite List (4 * n octets) (default: CCMP) + * Authenticated Key Management Suite Count (2 octets, little endian) + * (default: 1) + * Authenticated Key Management Suite List (4 * n octets) + * (default: unspec 802.1X) + * RSN Capabilities (2 octets, little endian) (default: 0) + * PMKID Count (2 octets) (default: 0) + * PMKID List (16 * n octets) + * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC) + */ + +struct rsn_ie_hdr { + u8 elem_id; /* WLAN_EID_RSN */ + u8 len; + u8 version[2]; /* little endian */ +} STRUCT_PACKED; + + +#ifdef CONFIG_PEERKEY +enum { + STK_MUI_4WAY_STA_AP = 1, + STK_MUI_4WAY_STAT_STA = 2, + STK_MUI_GTK = 3, + STK_MUI_SMK = 4 +}; + +enum { + STK_ERR_STA_NR = 1, + STK_ERR_STA_NRSN = 2, + STK_ERR_CPHR_NS = 3, + STK_ERR_NO_STSL = 4 +}; +#endif /* CONFIG_PEERKEY */ + +struct rsn_error_kde { + be16 mui; + be16 error_type; +} STRUCT_PACKED; + +#ifdef CONFIG_IEEE80211W +struct wpa_igtk_kde { + u8 keyid[2]; + u8 pn[6]; + u8 igtk[WPA_IGTK_LEN]; +} STRUCT_PACKED; +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_IEEE80211R +struct rsn_mdie { + u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; + u8 ft_capab; +} STRUCT_PACKED; + +#define RSN_FT_CAPAB_FT_OVER_DS BIT(0) +#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1) + +struct rsn_ftie { + u8 mic_control[2]; + u8 mic[16]; + u8 anonce[WPA_NONCE_LEN]; + u8 snonce[WPA_NONCE_LEN]; + /* followed by optional parameters */ +} STRUCT_PACKED; + +#define FTIE_SUBELEM_R1KH_ID 1 +#define FTIE_SUBELEM_GTK 2 +#define FTIE_SUBELEM_R0KH_ID 3 +#define FTIE_SUBELEM_IGTK 4 + +struct rsn_rdie { + u8 id; + u8 descr_count; + le16 status_code; +} STRUCT_PACKED; + +#endif /* CONFIG_IEEE80211R */ + +struct wpa_ie_data { + int proto; + int pairwise_cipher; + int group_cipher; + int key_mgmt; + int capabilities; + size_t num_pmkid; + const u8 *pmkid; + int mgmt_group_cipher; +}; + +const char * wpa_cipher_txt(int cipher); + +int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, + struct wpa_ie_data *data); + +int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, + u8 *mic); +int wpa_compare_rsn_ie(int ft_initial_assoc, + const u8 *ie1, size_t ie1len, + const u8 *ie2, size_t ie2len); + +void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, + const u8 *addr1, const u8 *addr2, + const u8 *nonce1, const u8 *nonce2, + u8 *ptk, size_t ptk_len, int use_sha256); + +void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, + u8 *pmkid, int use_sha256); + +#endif /* WPA_COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_debug.h b/components/wpa_supplicant/include/wpa/wpa_debug.h new file mode 100644 index 0000000000..b78a657e05 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_debug.h @@ -0,0 +1,193 @@ +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_DEBUG_H +#define WPA_DEBUG_H + + +enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR }; + +/** EAP authentication completed successfully */ +#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " + +int wpa_debug_open_file(const char *path); +void wpa_debug_close_file(void); + +/** + * wpa_debug_printf_timestamp - Print timestamp for debug output + * + * This function prints a timestamp in seconds_from_1970.microsoconds + * format if debug output has been configured to include timestamps in debug + * messages. + */ +void wpa_debug_print_timestamp(void); + +/** + * wpa_printf - conditional printf + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +//#define DEBUG_PRINT +//#define MSG_PRINT + +/** + * wpa_hexdump - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. + */ +#ifdef DEBUG_PRINT +#define wpa_printf(level,fmt, args...) ets_printf(fmt,## args) + +static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) +{ + +} + +static inline void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, size_t len) +{ +} + + +void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); + +static inline void wpa_hexdump_buf(int level, const char *title, + const struct wpabuf *buf) +{ + wpa_hexdump(level, title, wpabuf_head(buf), wpabuf_len(buf)); +} + +/** + * wpa_hexdump_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. This works + * like wpa_hexdump(), but by default, does not include secret keys (passwords, + * etc.) in debug output. + */ +void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); + + +static inline void wpa_hexdump_buf_key(int level, const char *title, + const struct wpabuf *buf) +{ + wpa_hexdump_key(level, title, wpabuf_head(buf), wpabuf_len(buf)); +} + +/** + * wpa_hexdump_ascii - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. + */ +void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, + size_t len); + +/** + * wpa_hexdump_ascii_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by + * default, does not include secret keys (passwords, etc.) in debug output. + */ +void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, + size_t len); +#else +#define wpa_printf(level,fmt, args...) +#define wpa_hexdump(...) +#define wpa_hexdump_buf(...) +#define wpa_hexdump_key(...) +#define wpa_hexdump_buf_key(...) +#define wpa_hexdump_ascii(...) +#define wpa_hexdump_ascii_key(...) +#endif + +#define wpa_auth_logger +#define wpa_auth_vlogger + +/** + * wpa_msg - Conditional printf for default target and ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. This function is like wpa_printf(), but it also sends the + * same message to all attached ctrl_iface monitors. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output only to the + * attached ctrl_iface monitors. In other words, it can be used for frequent + * events that do not need to be sent to syslog. + */ +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt, + size_t len); + +typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx); + +int eloop_cancel_timeout(eloop_timeout_handler handler, + void *eloop_data, void *user_data); + +int eloop_register_timeout(unsigned int secs, unsigned int usecs, + eloop_timeout_handler handler, + void *eloop_data, void *user_data); + + +#endif /* WPA_DEBUG_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa_i.h b/components/wpa_supplicant/include/wpa/wpa_i.h new file mode 100644 index 0000000000..a43c33d332 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_i.h @@ -0,0 +1,89 @@ +/* + * Internal WPA/RSN supplicant state machine definitions + * Copyright (c) 2004-2010, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_I_H +#define WPA_I_H + +/** + * set_key - Configure encryption key + * @ifname: Interface name (for multi-SSID/VLAN support) + * @priv: private driver interface data + * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, + * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK); + * %WPA_ALG_NONE clears the key. + * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for + * broadcast/default keys + * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for + * IGTK + * @set_tx: configure this key as the default Tx key (only used when + * driver does not support separate unicast/individual key + * @seq: sequence number/packet number, seq_len octets, the next + * packet number to be used for in replay protection; configured + * for Rx keys (in most cases, this is only used with broadcast + * keys and set to zero for unicast keys) + * @seq_len: length of the seq, depends on the algorithm: + * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets + * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, + * 8-byte Rx Mic Key + * @key_len: length of the key buffer in octets (WEP: 5 or 13, + * TKIP: 32, CCMP: 16, IGTK: 16) + * + * Returns: 0 on success, -1 on failure + * + * Configure the given key for the kernel driver. If the driver + * supports separate individual keys (4 default keys + 1 individual), + * addr can be used to determine whether the key is default or + * individual. If only 4 keys are supported, the default key with key + * index 0 is used as the individual key. STA must be configured to use + * it as the default Tx key (set_tx is set) and accept Rx for all the + * key indexes. In most cases, WPA uses only key indexes 1 and 2 for + * broadcast keys, so key index 0 is available for this kind of + * configuration. + * + * Please note that TKIP keys include separate TX and RX MIC keys and + * some drivers may expect them in different order than wpa_supplicant + * is using. If the TX/RX keys are swapped, all TKIP encrypted packets + * will tricker Michael MIC errors. This can be fixed by changing the + * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key + * in driver_*.c set_key() implementation, see driver_ndis.c for an + * example on how this can be done. + */ + +typedef void (* WPA_SEND_FUNC)(struct pbuf *pb); + +typedef void (* WPA_SET_ASSOC_IE)(uint8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); + +typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, uint8 *addr, int key_idx, int set_tx, + uint8 *seq, size_t seq_len, uint8 *key, size_t key_len, int key_entry_valid); + +typedef void (*WPA_DEAUTH)(uint8 reason_code); + +typedef void (*WPA_NEG_COMPLETE)(); + +void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \ + WPA_SET_ASSOC_IE set_assoc_ie_func, \ + WPA_INSTALL_KEY ppinstallkey, \ + WPA_DEAUTH wpa_deauth, \ + WPA_NEG_COMPLETE wpa_neg_complete); + +#include "pp/esf_buf.h" +void eapol_txcb(esf_buf_t *eb); + +void wpa_set_profile(uint32 wpa_proto); + +void wpa_set_bss(char *macddr, char * bssid, uint8 pairwise_cipher, uint8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len); + +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); +#endif /* WPA_I_H */ + diff --git a/components/wpa_supplicant/include/wpa/wpa_ie.h b/components/wpa_supplicant/include/wpa/wpa_ie.h new file mode 100644 index 0000000000..94518d8457 --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpa_ie.h @@ -0,0 +1,56 @@ +/* + * wpa_supplicant - WPA/RSN IE and KDE definitions + * Copyright (c) 2004-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_IE_H +#define WPA_IE_H + +struct wpa_eapol_ie_parse { + const u8 *wpa_ie; + size_t wpa_ie_len; + const u8 *rsn_ie; + size_t rsn_ie_len; + const u8 *pmkid; + const u8 *gtk; + size_t gtk_len; + const u8 *mac_addr; + size_t mac_addr_len; +#ifdef CONFIG_PEERKEY + const u8 *smk; + size_t smk_len; + const u8 *nonce; + size_t nonce_len; + const u8 *lifetime; + size_t lifetime_len; + const u8 *error; + size_t error_len; +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211W + const u8 *igtk; + size_t igtk_len; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R + const u8 *mdie; + size_t mdie_len; + const u8 *ftie; + size_t ftie_len; + const u8 *reassoc_deadline; + const u8 *key_lifetime; +#endif /* CONFIG_IEEE80211R */ +}; + +int wpa_supplicant_parse_ies(const u8 *buf, size_t len, + struct wpa_eapol_ie_parse *ie); +int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len); + +#endif /* WPA_IE_H */ diff --git a/components/wpa_supplicant/include/wpa/wpabuf.h b/components/wpa_supplicant/include/wpa/wpabuf.h new file mode 100644 index 0000000000..cccfcc80ef --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpabuf.h @@ -0,0 +1,168 @@ +/* + * Dynamic data buffer + * Copyright (c) 2007-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPABUF_H +#define WPABUF_H + +/* + * Internal data structure for wpabuf. Please do not touch this directly from + * elsewhere. This is only defined in header file to allow inline functions + * from this file to access data. + */ +struct wpabuf { + size_t size; /* total size of the allocated buffer */ + size_t used; /* length of data in the buffer */ + u8 *ext_data; /* pointer to external data; NULL if data follows + * struct wpabuf */ + /* optionally followed by the allocated buffer */ +}; + + +int wpabuf_resize(struct wpabuf **buf, size_t add_len); +struct wpabuf * wpabuf_alloc(size_t len); +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); +struct wpabuf * wpabuf_dup(const struct wpabuf *src); +void wpabuf_free(struct wpabuf *buf); +void * wpabuf_put(struct wpabuf *buf, size_t len); +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); +void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); + + +/** + * wpabuf_size - Get the currently allocated size of a wpabuf buffer + * @buf: wpabuf buffer + * Returns: Currently allocated size of the buffer + */ +static inline size_t wpabuf_size(const struct wpabuf *buf) +{ + return buf->size; +} + +/** + * wpabuf_len - Get the current length of a wpabuf buffer data + * @buf: wpabuf buffer + * Returns: Currently used length of the buffer + */ +static inline size_t wpabuf_len(const struct wpabuf *buf) +{ + return buf->used; +} + +/** + * wpabuf_tailroom - Get size of available tail room in the end of the buffer + * @buf: wpabuf buffer + * Returns: Tail room (in bytes) of available space in the end of the buffer + */ +static inline size_t wpabuf_tailroom(const struct wpabuf *buf) +{ + return buf->size - buf->used; +} + +/** + * wpabuf_head - Get pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline const void * wpabuf_head(const struct wpabuf *buf) +{ + if (buf->ext_data) + return buf->ext_data; + return buf + 1; +} + +static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) +{ + return wpabuf_head(buf); +} + +/** + * wpabuf_mhead - Get modifiable pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline void * wpabuf_mhead(struct wpabuf *buf) +{ + if (buf->ext_data) + return buf->ext_data; + return buf + 1; +} + +static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) +{ + return wpabuf_mhead(buf); +} + +static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) +{ + u8 *pos = wpabuf_put(buf, 1); + *pos = data; +} + +static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) +{ + u8 *pos = wpabuf_put(buf, 2); + WPA_PUT_LE16(pos, data); +} + +static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) +{ + u8 *pos = wpabuf_put(buf, 4); + WPA_PUT_LE32(pos, data); +} + +static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) +{ + u8 *pos = wpabuf_put(buf, 2); + WPA_PUT_BE16(pos, data); +} + +static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) +{ + u8 *pos = wpabuf_put(buf, 3); + WPA_PUT_BE24(pos, data); +} + +static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) +{ + u8 *pos = wpabuf_put(buf, 4); + WPA_PUT_BE32(pos, data); +} + +static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, + size_t len) +{ + if (data) + os_memcpy(wpabuf_put(buf, len), data, len); +} + +static inline void wpabuf_put_buf(struct wpabuf *dst, + const struct wpabuf *src) +{ + wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); +} + +static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) +{ + buf->ext_data = (u8 *) data; + buf->size = buf->used = len; +} + +static inline void wpabuf_put_str(struct wpabuf *dst, const char *str) +{ + wpabuf_put_data(dst, str, os_strlen(str)); +} + +#endif /* WPABUF_H */ diff --git a/components/wpa_supplicant/include/wpa/wpas_glue.h b/components/wpa_supplicant/include/wpa/wpas_glue.h new file mode 100644 index 0000000000..7e254a2d7d --- /dev/null +++ b/components/wpa_supplicant/include/wpa/wpas_glue.h @@ -0,0 +1,31 @@ +/* + * WPA Supplicant - Glue code to setup EAPOL and RSN modules + * Copyright (c) 2003-2008, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPAS_GLUE_H +#define WPAS_GLUE_H + +u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos); + +int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr, + int protect_type, int key_type); + +void wpa_sm_deauthenticate(struct wpa_sm *sm, uint8 reason_code); + +void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code); + +int wpa_sm_get_beacon_ie(struct wpa_sm *sm); + +#endif /* WPAS_GLUE_H */ diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap.h b/components/wpa_supplicant/include/wpa2/eap_peer/eap.h new file mode 100644 index 0000000000..e2cd2dd81d --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/eap_peer/eap.h @@ -0,0 +1,24 @@ +/* + * EAP peer state machine functions (RFC 4137) + * Copyright (c) 2004-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_H +#define EAP_H + +#include "wpa/defs.h" +#include "eap/eap_defs.h" + +struct eap_sm; + +struct eap_method_type { + int vendor; + u32 method; +}; + +const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); + +#endif /* EAP_H */ diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h b/components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h new file mode 100644 index 0000000000..38c5710058 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h @@ -0,0 +1,23 @@ +/* + * EAP common peer/server definitions + * Copyright (c) 2004-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_COMMON_H +#define EAP_COMMON_H + +#include "wpa/wpabuf.h" + +int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload); +const u8 * eap_hdr_validate(int vendor, EapType eap_type, + const struct wpabuf *msg, size_t *plen); +struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, + u8 code, u8 identifier); +void eap_update_len(struct wpabuf *msg); +u8 eap_get_id(const struct wpabuf *msg); +EapType eap_get_type(const struct wpabuf *msg); + +#endif /* EAP_COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h b/components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h new file mode 100644 index 0000000000..f35cbf43d7 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h @@ -0,0 +1,220 @@ +/* + * EAP peer configuration data + * Copyright (c) 2003-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_CONFIG_H +#define EAP_CONFIG_H + +/** + * struct eap_peer_config - EAP peer configuration/credentials + */ +struct eap_peer_config { + /** + * identity - EAP Identity + * + * This field is used to set the real user identity or NAI (for + * EAP-PSK/PAX/SAKE/GPSK). + */ + u8 *identity; + + /** + * identity_len - EAP Identity length + */ + size_t identity_len; + + /** + * password - Password string for EAP + * + * This field can include either the plaintext password (default + * option) or a NtPasswordHash (16-byte MD4 hash of the unicode + * presentation of the password) if flags field has + * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can + * only be used with authentication mechanism that use this hash as the + * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2, + * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). + * + * In addition, this field is used to configure a pre-shared key for + * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK + * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length + * PSK. + */ + u8 *password; + + /** + * password_len - Length of password field + */ + size_t password_len; + + /** + * ca_cert - File path to CA certificate file (PEM/DER) + * + * This file can have one or more trusted CA certificates. If ca_cert + * and ca_path are not included, server certificate will not be + * verified. This is insecure and a trusted CA certificate should + * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + * + * Alternatively, this can be used to only perform matching of the + * server certificate (SHA-256 hash of the DER encoded X.509 + * certificate). In this case, the possible CA certificates in the + * server certificate chain are ignored and only the server certificate + * is verified. This is configured with the following format: + * hash:://server/sha256/cert_hash_in_hex + * For example: "hash://server/sha256/ + * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" + * + * On Windows, trusted CA certificates can be loaded from the system + * certificate store by setting this to cert_store://name, e.g., + * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". + * Note that when running wpa_supplicant as an application, the user + * certificate store (My user account) is used, whereas computer store + * (Computer account) is used when running wpasvc as a service. + */ + u8 *ca_cert; + + /** + * ca_path - Directory path for CA certificate files (PEM) + * + * This path may contain multiple CA certificates in OpenSSL format. + * Common use for this is to point to system trusted CA list which is + * often installed into directory like /etc/ssl/certs. If configured, + * these certificates are added to the list of trusted CAs. ca_cert + * may also be included in that case, but it is not required. + */ + u8 *ca_path; + + /** + * client_cert - File path to client certificate file (PEM/DER) + * + * This field is used with EAP method that use TLS authentication. + * Usually, this is only configured for EAP-TLS, even though this could + * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *client_cert; + + /** + * private_key - File path to client private key file (PEM/DER/PFX) + * + * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be + * commented out. Both the private key and certificate will be read + * from the PKCS#12 file in this case. Full path to the file should be + * used since working directory may change when wpa_supplicant is run + * in the background. + * + * Windows certificate store can be used by leaving client_cert out and + * configuring private_key in one of the following formats: + * + * cert://substring_to_match + * + * hash://certificate_thumbprint_in_hex + * + * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" + * + * Note that when running wpa_supplicant as an application, the user + * certificate store (My user account) is used, whereas computer store + * (Computer account) is used when running wpasvc as a service. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *private_key; + + /** + * private_key_passwd - Password for private key file + * + * If left out, this will be asked through control interface. + */ + u8 *private_key_passwd; + + char *phase1; + + /** + * pin - PIN for USIM, GSM SIM, and smartcards + * + * This field is used to configure PIN for SIM and smartcards for + * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a + * smartcard is used for private key operations. + * + * If left out, this will be asked through control interface. + */ + char *pin; + + /** + * fragment_size - Maximum EAP fragment size in bytes (default 1398) + * + * This value limits the fragment size for EAP methods that support + * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set + * small enough to make the EAP messages fit in MTU of the network + * interface used for EAPOL. The default value is suitable for most + * cases. + */ + int fragment_size; + +#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0) +#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1) + /** + * flags - Network configuration flags (bitfield) + * + * This variable is used for internal flags to describe further details + * for the network parameters. + * bit 0 = password is represented as a 16-byte NtPasswordHash value + * instead of plaintext password + * bit 1 = password is stored in external storage; the value in the + * password field is the name of that external entry + */ + u32 flags; + + /** + * ocsp - Whether to use/require OCSP to check server certificate + * + * 0 = do not use OCSP stapling (TLS certificate status extension) + * 1 = try to use OCSP stapling, but not require response + * 2 = require valid OCSP stapling response + */ + int ocsp; +}; + + +/** + * struct wpa_config_blob - Named configuration blob + * + * This data structure is used to provide storage for binary objects to store + * abstract information like certificates and private keys inlined with the + * configuration data. + */ +struct wpa_config_blob { + /** + * name - Blob name + */ + char *name; + + /** + * data - Pointer to binary data + */ + u8 *data; + + /** + * len - Length of binary data + */ + size_t len; + + /** + * next - Pointer to next blob in the configuration + */ + struct wpa_config_blob *next; +}; + +#endif /* EAP_CONFIG_H */ diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_defs.h b/components/wpa_supplicant/include/wpa2/eap_peer/eap_defs.h new file mode 100644 index 0000000000..10995d3868 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/eap_peer/eap_defs.h @@ -0,0 +1,92 @@ +/* + * EAP server/peer: Shared EAP definitions + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_DEFS_H +#define EAP_DEFS_H + +/* RFC 3748 - Extensible Authentication Protocol (EAP) */ + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_hdr { + u8 code; + u8 identifier; + be16 length; /* including code and identifier; network byte order */ + /* followed by length-4 octets of data */ +} STRUCT_PACKED; + + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, + EAP_CODE_FAILURE = 4 }; + +/* EAP Request and Response data begins with one octet Type. Success and + * Failure do not have additional data. */ + +/* + * EAP Method Types as allocated by IANA: + * http://www.iana.org/assignments/eap-numbers + */ +typedef enum { + EAP_TYPE_NONE = 0, + EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, + EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, + EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */, + EAP_TYPE_MD5 = 4, /* RFC 3748 */ + EAP_TYPE_OTP = 5 /* RFC 3748 */, + EAP_TYPE_GTC = 6, /* RFC 3748 */ + EAP_TYPE_TLS = 13 /* RFC 2716 */, + EAP_TYPE_LEAP = 17 /* Cisco proprietary */, + EAP_TYPE_SIM = 18 /* RFC 4186 */, + EAP_TYPE_TTLS = 21 /* RFC 5281 */, + EAP_TYPE_AKA = 23 /* RFC 4187 */, + EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */, + EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */, + EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */, + EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment; + * type 38 has previously been allocated for + * EAP-HTTP Digest, (funk.com) */, + EAP_TYPE_FAST = 43 /* RFC 4851 */, + EAP_TYPE_PAX = 46 /* RFC 4746 */, + EAP_TYPE_PSK = 47 /* RFC 4764 */, + EAP_TYPE_SAKE = 48 /* RFC 4763 */, + EAP_TYPE_IKEV2 = 49 /* RFC 5106 */, + EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */, + EAP_TYPE_GPSK = 51 /* RFC 5433 */, + EAP_TYPE_PWD = 52 /* RFC 5931 */, + EAP_TYPE_EKE = 53 /* RFC 6124 */, + EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ +} EapType; + + +/* SMI Network Management Private Enterprise Code for vendor specific types */ +enum { + EAP_VENDOR_IETF = 0, + EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */, + EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */, + EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */ +}; + +struct eap_expand { + u8 vendor_id[3]; + be32 vendor_type; + u8 opcode; +} STRUCT_PACKED; + +#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP +#define EAP_VENDOR_TYPE_UNAUTH_TLS 1 + +#define EAP_MSK_LEN 64 +#define EAP_EMSK_LEN 64 + +#endif /* EAP_DEFS_H */ diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h b/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h new file mode 100644 index 0000000000..a4779d13f8 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h @@ -0,0 +1,88 @@ +/* + * EAP peer state machines internal structures (RFC 4137) + * Copyright (c) 2004-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_I_H +#define EAP_I_H + +#include "wpa/wpabuf.h" +#include "eap.h" +#include "eap_common.h" +#include "eap_config.h" + +/* RFC 4137 - EAP Peer state machine */ + +typedef enum { + DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC +} EapDecision; + +typedef enum { + METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE +} EapMethodState; + +/** + * struct eap_method_ret - EAP return values from struct eap_method::process() + * + * These structure contains OUT variables for the interface between peer state + * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as + * the return value of struct eap_method::process() so it is not included in + * this structure. + */ +struct eap_method_ret { + /** + * ignore - Whether method decided to drop the current packed (OUT) + */ + Boolean ignore; + + /** + * methodState - Method-specific state (IN/OUT) + */ + EapMethodState methodState; + + /** + * decision - Authentication decision (OUT) + */ + EapDecision decision; + + /** + * allowNotifications - Whether method allows notifications (OUT) + */ + Boolean allowNotifications; +}; + +#define CLIENT_CERT_NAME "CLC" +#define CA_CERT_NAME "CAC" +#define PRIVATE_KEY_NAME "PVK" +#define BLOB_NAME_LEN 3 +#define BLOB_NUM 2 + +/** + * struct eap_sm - EAP state machine data + */ +struct eap_sm { + void *eap_method_priv; + + void *ssl_ctx; + + unsigned int workaround; +///////////////////////////////////////////////// + struct pbuf *outbuf; + struct wpa_config_blob blob[BLOB_NUM]; + struct eap_peer_config config; + u8 current_identifier; + u8 ownaddr[ETH_ALEN]; +#ifdef USE_WPA2_TASK +#define SIG_WPA2_NUM 2 + u8 wpa2_sig_cnt[SIG_WPA2_NUM]; +#endif + u8 finish_state; +}; + +struct eap_peer_config * eap_get_config(struct eap_sm *sm); +const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm, const char *name); + +#endif /* EAP_I_H */ diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls.h b/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls.h new file mode 100644 index 0000000000..a8a386f22c --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls.h @@ -0,0 +1,25 @@ +/* + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions + * Copyright (c) 2004-2009, 2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_TLS_H +#define EAP_TLS_H + +#include "eap_i.h" +#include "eap_common.h" +#include "eap.h" +#include "wpa/wpabuf.h" + +void * eap_tls_init(struct eap_sm *sm); +void eap_tls_deinit(struct eap_sm *sm, void *priv); +struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, + struct eap_method_ret *ret, + const struct wpabuf *reqData); + +u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len); + +#endif /* EAP_TLS_H */ diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls_common.h b/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls_common.h new file mode 100644 index 0000000000..1a5e0f89e4 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/eap_peer/eap_tls_common.h @@ -0,0 +1,131 @@ +/* + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions + * Copyright (c) 2004-2009, 2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EAP_TLS_COMMON_H +#define EAP_TLS_COMMON_H + +/** + * struct eap_ssl_data - TLS data for EAP methods + */ +struct eap_ssl_data { + /** + * conn - TLS connection context data from tls_connection_init() + */ + struct tls_connection *conn; + + /** + * tls_out - TLS message to be sent out in fragments + */ + struct wpabuf *tls_out; + + /** + * tls_out_pos - The current position in the outgoing TLS message + */ + size_t tls_out_pos; + + /** + * tls_out_limit - Maximum fragment size for outgoing TLS messages + */ + size_t tls_out_limit; + + /** + * tls_in - Received TLS message buffer for re-assembly + */ + struct wpabuf *tls_in; + + /** + * tls_in_left - Number of remaining bytes in the incoming TLS message + */ + size_t tls_in_left; + + /** + * tls_in_total - Total number of bytes in the incoming TLS message + */ + size_t tls_in_total; + + /** + * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) + */ + int phase2; + + /** + * include_tls_length - Whether the TLS length field is included even + * if the TLS data is not fragmented + */ + int include_tls_length; + + /** + * eap - EAP state machine allocated with eap_peer_sm_init() + */ + struct eap_sm *eap; + + /** + * ssl_ctx - TLS library context to use for the connection + */ + void *ssl_ctx; + + /** + * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) + */ + u8 eap_type; +}; + + +/* EAP TLS Flags */ +#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 +#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 +#define EAP_TLS_FLAGS_START 0x20 +#define EAP_TLS_VERSION_MASK 0x07 + + /* could be up to 128 bytes, but only the first 64 bytes are used */ +#define EAP_TLS_KEY_LEN 64 + +/* dummy type used as a flag for UNAUTH-TLS */ +#define EAP_UNAUTH_TLS_TYPE 255 + + +int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, + struct eap_peer_config *config, u8 eap_type); +void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); +u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, + const char *label, size_t len); +u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, + struct eap_ssl_data *data, u8 eap_type, + size_t *len); +int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, + EapType eap_type, int peap_version, + u8 id, const u8 *in_data, size_t in_len, + struct wpabuf **out_data); +struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, + int peap_version); +int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data); +int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, + char *buf, size_t buflen, int verbose); +const u8 * eap_peer_tls_process_init(struct eap_sm *sm, + struct eap_ssl_data *data, + EapType eap_type, + struct eap_method_ret *ret, + const struct wpabuf *reqData, + size_t *len, u8 *flags); +void eap_peer_tls_reset_input(struct eap_ssl_data *data); +void eap_peer_tls_reset_output(struct eap_ssl_data *data); +int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, + const struct wpabuf *in_data, + struct wpabuf **in_decrypted); +int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, + EapType eap_type, int peap_version, u8 id, + const struct wpabuf *in_data, + struct wpabuf **out_data); +int eap_peer_select_phase2_methods(struct eap_peer_config *config, + const char *prefix, + struct eap_method_type **types, + size_t *num_types); +int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, + struct eap_hdr *hdr, struct wpabuf **resp); + +#endif /* EAP_TLS_COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/asn1.h b/components/wpa_supplicant/include/wpa2/tls/asn1.h new file mode 100644 index 0000000000..6342c4cc79 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/asn1.h @@ -0,0 +1,66 @@ +/* + * ASN.1 DER parsing + * Copyright (c) 2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef ASN1_H +#define ASN1_H + +#define ASN1_TAG_EOC 0x00 /* not used with DER */ +#define ASN1_TAG_BOOLEAN 0x01 +#define ASN1_TAG_INTEGER 0x02 +#define ASN1_TAG_BITSTRING 0x03 +#define ASN1_TAG_OCTETSTRING 0x04 +#define ASN1_TAG_NULL 0x05 +#define ASN1_TAG_OID 0x06 +#define ASN1_TAG_OBJECT_DESCRIPTOR 0x07 /* not yet parsed */ +#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */ +#define ASN1_TAG_REAL 0x09 /* not yet parsed */ +#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */ +#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */ +#define ANS1_TAG_RELATIVE_OID 0x0D +#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */ +#define ASN1_TAG_SET 0x11 +#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */ +#define ASN1_TAG_PRINTABLESTRING 0x13 +#define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */ +#define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */ +#define ASN1_TAG_IA5STRING 0x16 +#define ASN1_TAG_UTCTIME 0x17 +#define ASN1_TAG_GENERALIZEDTIME 0x18 /* not yet parsed */ +#define ASN1_TAG_GRAPHICSTRING 0x19 /* not yet parsed */ +#define ASN1_TAG_VISIBLESTRING 0x1A +#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */ +#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */ +#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */ + +#define ASN1_CLASS_UNIVERSAL 0 +#define ASN1_CLASS_APPLICATION 1 +#define ASN1_CLASS_CONTEXT_SPECIFIC 2 +#define ASN1_CLASS_PRIVATE 3 + + +struct asn1_hdr { + const u8 *payload; + u8 identifier, class, constructed; + unsigned int tag, length; +}; + +#define ASN1_MAX_OID_LEN 20 +struct asn1_oid { + unsigned long oid[ASN1_MAX_OID_LEN]; + size_t len; +}; + + +int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr); +int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid); +int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, + const u8 **next); +void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len); +unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len); + +#endif /* ASN1_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/bignum.h b/components/wpa_supplicant/include/wpa2/tls/bignum.h new file mode 100644 index 0000000000..f25e26783a --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/bignum.h @@ -0,0 +1,38 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef BIGNUM_H +#define BIGNUM_H + +struct bignum; + +struct bignum * bignum_init(void); +void bignum_deinit(struct bignum *n); +size_t bignum_get_unsigned_bin_len(struct bignum *n); +int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len); +int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len); +int bignum_cmp(const struct bignum *a, const struct bignum *b); +int bignum_cmp_d(const struct bignum *a, unsigned long b); +int bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); +int bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); + +#endif /* BIGNUM_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/libtommath.h b/components/wpa_supplicant/include/wpa2/tls/libtommath.h new file mode 100644 index 0000000000..c0409b5e33 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/libtommath.h @@ -0,0 +1,3443 @@ +/* + * Minimal code for RSA support from LibTomMath 0.41 + * http://libtom.org/ + * http://libtom.org/files/ltm-0.41.tar.bz2 + * This library was released in public domain by Tom St Denis. + * + * The combination in this file may not use all of the optimized algorithms + * from LibTomMath and may be considerable slower than the LibTomMath with its + * default settings. The main purpose of having this version here is to make it + * easier to build bignum.c wrapper without having to install and build an + * external library. + * + * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this + * libtommath.c file instead of using the external LibTomMath library. + */ +#include "c_types.h" +#include "os.h" +#include "stdarg.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#define BN_MP_INVMOD_C +#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would + * require BN_MP_EXPTMOD_FAST_C instead */ +#define BN_S_MP_MUL_DIGS_C +#define BN_MP_INVMOD_SLOW_C +#define BN_S_MP_SQR_C +#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this + * would require other than mp_reduce */ + +#ifdef LTM_FAST + +/* Use faster div at the cost of about 1 kB */ +#define BN_MP_MUL_D_C + +/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */ +#define BN_MP_EXPTMOD_FAST_C +#define BN_MP_MONTGOMERY_SETUP_C +#define BN_FAST_MP_MONTGOMERY_REDUCE_C +#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +#define BN_MP_MUL_2_C + +/* Include faster sqr at the cost of about 0.5 kB in code */ +#define BN_FAST_S_MP_SQR_C + +#else /* LTM_FAST */ + +#define BN_MP_DIV_SMALL +#define BN_MP_INIT_MULTI_C +#define BN_MP_CLEAR_MULTI_C +#define BN_MP_ABS_C +#endif /* LTM_FAST */ + +/* Current uses do not require support for negative exponent in exptmod, so we + * can save about 1.5 kB in leaving out invmod. */ +#define LTM_NO_NEG_EXP + +/* from tommath.h */ + +#ifndef MIN + #define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef MAX + #define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#define OPT_CAST(x) (x *) + +typedef unsigned long mp_digit; +typedef u64 mp_word; + +#define DIGIT_BIT 28 +#define MP_28BIT + + +#define XMALLOC os_malloc +#define XFREE os_free +#define XREALLOC os_realloc + + +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) + +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ + +#define MP_YES 1 /* yes response */ +#define MP_NO 0 /* no response */ + +typedef int mp_err; + +/* define this to use lower memory usage routines (exptmods mostly) */ +#define MP_LOW_MEM + +/* default precision */ +#ifndef MP_PREC + #ifndef MP_LOW_MEM + #define MP_PREC 32 /* default digits of precision */ + #else + #define MP_PREC 8 /* default digits of precision */ + #endif +#endif + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) +#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) + + +/* prototypes for copied functions */ +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); +static int s_mp_sqr(mp_int * a, mp_int * b); +static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs); + +static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); + +#ifdef BN_MP_INIT_MULTI_C +static int mp_init_multi(mp_int *mp, ...); +#endif +#ifdef BN_MP_CLEAR_MULTI_C +static void mp_clear_multi(mp_int *mp, ...); +#endif +static int mp_lshd(mp_int * a, int b); +static void mp_set(mp_int * a, mp_digit b); +static void mp_clamp(mp_int * a); +static void mp_exch(mp_int * a, mp_int * b); +static void mp_rshd(mp_int * a, int b); +static void mp_zero(mp_int * a); +static int mp_mod_2d(mp_int * a, int b, mp_int * c); +static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d); +static int mp_init_copy(mp_int * a, mp_int * b); +static int mp_mul_2d(mp_int * a, int b, mp_int * c); +#ifndef LTM_NO_NEG_EXP +static int mp_div_2(mp_int * a, mp_int * b); +static int mp_invmod(mp_int * a, mp_int * b, mp_int * c); +static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c); +#endif /* LTM_NO_NEG_EXP */ +static int mp_copy(mp_int * a, mp_int * b); +static int mp_count_bits(mp_int * a); +static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); +static int mp_mod(mp_int * a, mp_int * b, mp_int * c); +static int mp_grow(mp_int * a, int size); +static int mp_cmp_mag(mp_int * a, mp_int * b); +#ifdef BN_MP_ABS_C +static int mp_abs(mp_int * a, mp_int * b); +#endif +static int mp_sqr(mp_int * a, mp_int * b); +static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); +static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); +static int mp_2expt(mp_int * a, int b); +static int mp_reduce_setup(mp_int * a, mp_int * b); +static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu); +static int mp_init_size(mp_int * a, int size); +#ifdef BN_MP_EXPTMOD_FAST_C +static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +#endif /* BN_MP_EXPTMOD_FAST_C */ +#ifdef BN_FAST_S_MP_SQR_C +static int fast_s_mp_sqr (mp_int * a, mp_int * b); +#endif /* BN_FAST_S_MP_SQR_C */ +#ifdef BN_MP_MUL_D_C +static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); +#endif /* BN_MP_MUL_D_C */ + + + +/* functions from bn_.c */ + + +/* reverse an array, used for radix code */ +static void ICACHE_FLASH_ATTR +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +static int ICACHE_FLASH_ATTR +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +static int ICACHE_FLASH_ATTR +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* init a new mp_int */ +static int ICACHE_FLASH_ATTR +mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + + +/* clear one (frees) */ +static void ICACHE_FLASH_ATTR +mp_clear (mp_int * a) +{ + int i; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + for (i = 0; i < a->used; i++) { + a->dp[i] = 0; + } + + /* free ram */ + XFREE(a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} + + +/* high level addition (handles signs) */ +static int ICACHE_FLASH_ATTR +mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* high level subtraction (handles signs) */ +static int ICACHE_FLASH_ATTR +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + + +/* high level multiplication (handles sign) */ +static int ICACHE_FLASH_ATTR +mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Toom-Cook? */ +#ifdef BN_MP_TOOM_MUL_C + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + } else +#endif +#ifdef BN_MP_KARATSUBA_MUL_C + /* use Karatsuba? */ + if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else +#endif + { + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ +#ifdef BN_FAST_S_MP_MUL_DIGS_C + int digs = a->used + b->used + 1; + + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else +#endif +#ifdef BN_S_MP_MUL_DIGS_C + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ +#else +#error mp_mul could fail + res = MP_VAL; +#endif + + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} + + +/* d = a * b (mod c) */ +static int ICACHE_FLASH_ATTR +mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + + +/* c = a mod b, 0 <= c < b */ +static int ICACHE_FLASH_ATTR +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted a lot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +static int ICACHE_FLASH_ATTR +mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { +#ifdef LTM_NO_NEG_EXP + return MP_VAL; +#else /* LTM_NO_NEG_EXP */ +#ifdef BN_MP_INVMOD_C + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; +#else +#error mp_exptmod would always fail + /* no invmod */ + return MP_VAL; +#endif +#endif /* LTM_NO_NEG_EXP */ + } + +/* modified diminished radix reduction */ +#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) + if (mp_reduce_is_2k_l(P) == MP_YES) { + return s_mp_exptmod(G, X, P, Y, 1); + } +#endif + +#ifdef BN_MP_DR_IS_MODULUS_C + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); +#else + /* default to no */ + dr = 0; +#endif + +#ifdef BN_MP_REDUCE_IS_2K_C + /* if not, is it a unrestricted DR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } +#endif + + /* if the modulus is odd or dr != 0 use the montgomery method */ +#ifdef BN_MP_EXPTMOD_FAST_C + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { +#endif +#ifdef BN_S_MP_EXPTMOD_C + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod (G, X, P, Y, 0); +#else +#error mp_exptmod could fail + /* no exptmod for evens */ + return MP_VAL; +#endif +#ifdef BN_MP_EXPTMOD_FAST_C + } +#endif +} + + +/* compare two ints (signed)*/ +static int ICACHE_FLASH_ATTR +mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + + +/* compare a digit */ +static int ICACHE_FLASH_ATTR +mp_cmp_d(mp_int * a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + + +#ifndef LTM_NO_NEG_EXP +/* hac 14.61, pp608 */ +static int ICACHE_FLASH_ATTR +mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + +#ifdef BN_FAST_MP_INVMOD_C + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } +#endif + +#ifdef BN_MP_INVMOD_SLOW_C + return mp_invmod_slow(a, b, c); +#endif + +#ifndef BN_FAST_MP_INVMOD_C +#ifndef BN_MP_INVMOD_SLOW_C +#error mp_invmod would always fail +#endif +#endif + return MP_VAL; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* get the size for an unsigned equivalent */ +static int ICACHE_FLASH_ATTR +mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + + +#ifndef LTM_NO_NEG_EXP +/* hac 14.61, pp608 */ +static int ICACHE_FLASH_ATTR +mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_mod(a, b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* compare maginitude of two ints (unsigned) */ +static int ICACHE_FLASH_ATTR +mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} + + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +static int ICACHE_FLASH_ATTR +mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + +#ifndef MP_8BIT + a->dp[0] |= *b++; + a->used += 1; +#else + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; +#endif + } + mp_clamp (a); + return MP_OKAY; +} + + +/* store in unsigned [big endian] format */ +static int ICACHE_FLASH_ATTR +mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { +#ifndef MP_8BIT + b[x++] = (unsigned char) (t.dp[0] & 255); +#else + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); +#endif + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +static int ICACHE_FLASH_ATTR +mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + + +static int ICACHE_FLASH_ATTR +mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + + +/* set to zero */ +static void ICACHE_FLASH_ATTR +mp_zero (mp_int * a) +{ + int n; + mp_digit *tmp; + + a->sign = MP_ZPOS; + a->used = 0; + + tmp = a->dp; + for (n = 0; n < a->alloc; n++) { + *tmp++ = 0; + } +} + + +/* copy, b = a */ +static int ICACHE_FLASH_ATTR +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + + +/* shift right a certain amount of digits */ +static void ICACHE_FLASH_ATTR +mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} + + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +static void ICACHE_FLASH_ATTR +mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +static void ICACHE_FLASH_ATTR +mp_clamp (mp_int * a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + + +/* grow as required */ +static int ICACHE_FLASH_ATTR +mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + + +#ifdef BN_MP_ABS_C +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +static int ICACHE_FLASH_ATTR +mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + + +/* set to a digit */ +static void ICACHE_FLASH_ATTR +mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + + +#ifndef LTM_NO_NEG_EXP +/* b = a/2 */ +static int ICACHE_FLASH_ATTR +mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* shift left by a certain bit count */ +static int ICACHE_FLASH_ATTR +mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +#ifdef BN_MP_INIT_MULTI_C +static int ICACHE_FLASH_ATTR +mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} +#endif + + +#ifdef BN_MP_CLEAR_MULTI_C +static void ICACHE_FLASH_ATTR +mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} +#endif + + +/* shift left a certain amount of digits */ +static int ICACHE_FLASH_ATTR +mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + + +/* returns the number of bits in an int */ +static int ICACHE_FLASH_ATTR +mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + + +/* calc a value mod 2**b */ +static int ICACHE_FLASH_ATTR +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b >= (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + + +#ifdef BN_MP_DIV_SMALL + +/* slower bit-bang division... also smaller */ +static int ICACHE_FLASH_ATTR +mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int ta, tb, tq, q; + int res, n, n2; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + /* init our temps */ + if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { + return res; + } + + + mp_set(&tq, 1); + n = mp_count_bits(a) - mp_count_bits(b); + if (((res = mp_abs(a, &ta)) != MP_OKAY) || + ((res = mp_abs(b, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { + goto LBL_ERR; + } + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || + ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { + goto LBL_ERR; + } + } + if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || + ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { + goto LBL_ERR; + } + } + + /* now q == quotient and ta == remainder */ + n = a->sign; + n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); + if (c != NULL) { + mp_exch(c, &q); + c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear_multi(&ta, &tb, &tq, &q, NULL); + return res; +} + +#else + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +static int ICACHE_FLASH_ATTR +mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto LBL_Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto LBL_T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto LBL_X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto LBL_Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto LBL_Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto LBL_Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = x.used == 0 ? MP_ZPOS : a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +LBL_Y:mp_clear (&y); +LBL_X:mp_clear (&x); +LBL_T2:mp_clear (&t2); +LBL_T1:mp_clear (&t1); +LBL_Q:mp_clear (&q); + return res; +} + +#endif + + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +static int ICACHE_FLASH_ATTR +s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_int*); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto LBL_M; + } + + if (redmode == 0) { + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce; + } else { + if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce_2k_l; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto LBL_MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + /* reduce modulo P */ + if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_MU; + } + if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_MU:mp_clear (&mu); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + + +/* computes b = a*a */ +static int ICACHE_FLASH_ATTR +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + +#ifdef BN_MP_TOOM_SQR_C + /* use Toom-Cook? */ + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + /* Karatsuba? */ + } else +#endif +#ifdef BN_MP_KARATSUBA_SQR_C +if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else +#endif + { +#ifdef BN_FAST_S_MP_SQR_C + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else +#endif +#ifdef BN_S_MP_SQR_C + res = s_mp_sqr (a, b); +#else +#error mp_sqr could fail + res = MP_VAL; +#endif + } + b->sign = MP_ZPOS; + return res; +} + + +/* reduces a modulo n where n is of the form 2**p - d + This differs from reduce_2k since "d" can be larger + than a single digit. +*/ +static int ICACHE_FLASH_ATTR +mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + /* q = q * d */ + if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + + +/* determines the setup value */ +static int ICACHE_FLASH_ATTR +mp_reduce_2k_setup_l(mp_int *a, mp_int *d) +{ + int res; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto ERR; + } + + if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear(&tmp); + return res; +} + + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +static int ICACHE_FLASH_ATTR +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accommodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} + + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +static int ICACHE_FLASH_ATTR +mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} + + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +static int ICACHE_FLASH_ATTR +mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { +#ifdef BN_S_MP_MUL_HIGH_DIGS_C + if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#else + { +#error mp_reduce would always fail + res = MP_VAL; + goto CLEANUP; + } +#endif + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + if ((res = mp_add (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + + +/* multiplies |a| * |b| and only computes up to digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +static int ICACHE_FLASH_ATTR +s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +static int ICACHE_FLASH_ATTR +fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + register mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa+1; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +/* init an mp_init for a given size */ +static int ICACHE_FLASH_ATTR +mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} + + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +static int ICACHE_FLASH_ATTR +s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* default used is maximum possible size */ + t.used = 2*pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[2*ix]) + + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (2*ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = ((mp_word) *tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +static int ICACHE_FLASH_ATTR +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } +#endif + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + + +#ifdef BN_MP_MONTGOMERY_SETUP_C +/* setups the montgomery reduction stuff */ +static int ICACHE_FLASH_ATTR +mp_montgomery_setup (mp_int * n, mp_digit * rho) +{ + mp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} +#endif + + +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int ICACHE_FLASH_ATTR +fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + register mp_digit mu; + mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + register int iy; + register mp_digit *tmpn; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MUL_2_C +/* b = a*2 */ +static int ICACHE_FLASH_ATTR +mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accommodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally up to just under + * the leading bit of b. This saves a lot of multiple precision shifting. + */ +static int ICACHE_FLASH_ATTR +mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_EXPTMOD_FAST_C +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +static int ICACHE_FLASH_ATTR +mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_SETUP_C + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto LBL_M; + } +#else + err = MP_VAL; + goto LBL_M; +#endif + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else +#endif + { +#ifdef BN_MP_MONTGOMERY_REDUCE_C + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + } else if (redmode == 1) { +#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } else { +#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto LBL_M; + } + redux = mp_reduce_2k; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_M; + } + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto LBL_RES; + } +#else + err = MP_VAL; + goto LBL_RES; +#endif + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* swap res with Y */ + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} +#endif + + +#ifdef BN_FAST_S_MP_SQR_C +/* the jist of squaring... + * you do like mult except the offset of the tmpx [one that + * starts closer to zero] can't equal the offset of tmpy. + * So basically you set up iy like before then you min it with + * (ty-tx) so that it never happens. You double all those + * you add in the inner loop + +After that loop you do the squares and add them in. +*/ + +static int ICACHE_FLASH_ATTR +fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* get offsets into the two bignums */ + ty = MIN(a->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = a->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach at a rate of 2x + * and we have to round because odd cases need to be executed + */ + iy = MIN(iy, (ty-tx+1)>>1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); + } + + /* store it */ + W[ix] = (mp_digit)(_W & MP_MASK); + + /* make next carry */ + W1 = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MUL_D_C +/* multiply by a digit */ +static int ICACHE_FLASH_ATTR +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} +#endif diff --git a/components/wpa_supplicant/include/wpa2/tls/pkcs1.h b/components/wpa_supplicant/include/wpa2/tls/pkcs1.h new file mode 100644 index 0000000000..ed64defaaf --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/pkcs1.h @@ -0,0 +1,22 @@ +/* + * PKCS #1 (RSA Encryption) + * Copyright (c) 2006-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef PKCS1_H +#define PKCS1_H + +int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, + int use_private, const u8 *in, size_t inlen, + u8 *out, size_t *outlen); +int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen); +int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, + const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len); + +#endif /* PKCS1_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/pkcs5.h b/components/wpa_supplicant/include/wpa2/tls/pkcs5.h new file mode 100644 index 0000000000..20ddadc457 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/pkcs5.h @@ -0,0 +1,16 @@ +/* + * PKCS #5 (Password-based Encryption) + * Copyright (c) 2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef PKCS5_H +#define PKCS5_H + +u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, + const u8 *enc_data, size_t enc_data_len, + const char *passwd, size_t *data_len); + +#endif /* PKCS5_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/pkcs8.h b/components/wpa_supplicant/include/wpa2/tls/pkcs8.h new file mode 100644 index 0000000000..bebf840ba7 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/pkcs8.h @@ -0,0 +1,16 @@ +/* + * PKCS #8 (Private-key information syntax) + * Copyright (c) 2006-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef PKCS8_H +#define PKCS8_H + +struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len); +struct crypto_private_key * +pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd); + +#endif /* PKCS8_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/rsa.h b/components/wpa_supplicant/include/wpa2/tls/rsa.h new file mode 100644 index 0000000000..c236a9df44 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/rsa.h @@ -0,0 +1,23 @@ +/* + * RSA + * Copyright (c) 2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef RSA_H +#define RSA_H + +struct crypto_rsa_key; + +struct crypto_rsa_key * +crypto_rsa_import_public_key(const u8 *buf, size_t len); +struct crypto_rsa_key * +crypto_rsa_import_private_key(const u8 *buf, size_t len); +size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key); +int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, + struct crypto_rsa_key *key, int use_private); +void crypto_rsa_free(struct crypto_rsa_key *key); + +#endif /* RSA_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/tls.h b/components/wpa_supplicant/include/wpa2/tls/tls.h new file mode 100644 index 0000000000..983999b51d --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/tls.h @@ -0,0 +1,537 @@ +/* + * SSL/TLS interface definition + * Copyright (c) 2004-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef TLS_H +#define TLS_H + +struct tls_connection; + +struct tls_keys { + const u8 *master_key; /* TLS master secret */ + size_t master_key_len; + const u8 *client_random; + size_t client_random_len; + const u8 *server_random; + size_t server_random_len; +}; + +enum tls_event { + TLS_CERT_CHAIN_SUCCESS, + TLS_CERT_CHAIN_FAILURE, + TLS_PEER_CERTIFICATE, + TLS_ALERT +}; + +/* + * Note: These are used as identifier with external programs and as such, the + * values must not be changed. + */ +enum tls_fail_reason { + TLS_FAIL_UNSPECIFIED = 0, + TLS_FAIL_UNTRUSTED = 1, + TLS_FAIL_REVOKED = 2, + TLS_FAIL_NOT_YET_VALID = 3, + TLS_FAIL_EXPIRED = 4, + TLS_FAIL_SUBJECT_MISMATCH = 5, + TLS_FAIL_ALTSUBJECT_MISMATCH = 6, + TLS_FAIL_BAD_CERTIFICATE = 7, + TLS_FAIL_SERVER_CHAIN_PROBE = 8 +}; + +union tls_event_data { + struct { + int depth; + const char *subject; + enum tls_fail_reason reason; + const char *reason_txt; + const struct wpabuf *cert; + } cert_fail; + + struct { + int depth; + const char *subject; + const struct wpabuf *cert; + const u8 *hash; + size_t hash_len; + } peer_cert; + + struct { + int is_local; + const char *type; + const char *description; + } alert; +}; + +struct tls_config { + const char *opensc_engine_path; + const char *pkcs11_engine_path; + const char *pkcs11_module_path; + int fips_mode; + int cert_in_cb; + + void (*event_cb)(void *ctx, enum tls_event ev, + union tls_event_data *data); + void *cb_ctx; +}; + +#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0) +#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1) +#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2) +#define TLS_CONN_REQUEST_OCSP BIT(3) +#define TLS_CONN_REQUIRE_OCSP BIT(4) + +/** + * struct tls_connection_params - Parameters for TLS connection + * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER + * format + * @ca_cert_blob: ca_cert as inlined data or %NULL if not used + * @ca_cert_blob_len: ca_cert_blob length + * @ca_path: Path to CA certificates (OpenSSL specific) + * @subject_match: String to match in the subject of the peer certificate or + * %NULL to allow all subjects + * @altsubject_match: String to match in the alternative subject of the peer + * certificate or %NULL to allow all alternative subjects + * @client_cert: File or reference name for client X.509 certificate in PEM or + * DER format + * @client_cert_blob: client_cert as inlined data or %NULL if not used + * @client_cert_blob_len: client_cert_blob length + * @private_key: File or reference name for client private key in PEM or DER + * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY) + * @private_key_blob: private_key as inlined data or %NULL if not used + * @private_key_blob_len: private_key_blob length + * @private_key_passwd: Passphrase for decrypted private key, %NULL if no + * passphrase is used. + * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used + * @dh_blob: dh_file as inlined data or %NULL if not used + * @dh_blob_len: dh_blob length + * @engine: 1 = use engine (e.g., a smartcard) for private key operations + * (this is OpenSSL specific for now) + * @engine_id: engine id string (this is OpenSSL specific for now) + * @ppin: pointer to the pin variable in the configuration + * (this is OpenSSL specific for now) + * @key_id: the private key's id when using engine (this is OpenSSL + * specific for now) + * @cert_id: the certificate's id when using engine + * @ca_cert_id: the CA certificate's id when using engine + * @flags: Parameter options (TLS_CONN_*) + * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response + * or %NULL if OCSP is not enabled + * + * TLS connection parameters to be configured with tls_connection_set_params() + * and tls_global_set_params(). + * + * Certificates and private key can be configured either as a reference name + * (file path or reference to certificate store) or by providing the same data + * as a pointer to the data in memory. Only one option will be used for each + * field. + */ +struct tls_connection_params { + const char *ca_cert; + const u8 *ca_cert_blob; + size_t ca_cert_blob_len; + const char *ca_path; + const char *subject_match; + const char *altsubject_match; + const char *client_cert; + const u8 *client_cert_blob; + size_t client_cert_blob_len; + const char *private_key; + const u8 *private_key_blob; + size_t private_key_blob_len; + const char *private_key_passwd; + const char *dh_file; + const u8 *dh_blob; + size_t dh_blob_len; + + /* OpenSSL specific variables */ + int engine; + const char *engine_id; + const char *pin; + const char *key_id; + const char *cert_id; + const char *ca_cert_id; + + unsigned int flags; + const char *ocsp_stapling_response; +}; + + +/** + * tls_init - Initialize TLS library + * @conf: Configuration data for TLS library + * Returns: Context data to be used as tls_ctx in calls to other functions, + * or %NULL on failure. + * + * Called once during program startup and once for each RSN pre-authentication + * session. In other words, there can be two concurrent TLS contexts. If global + * library initialization is needed (i.e., one that is shared between both + * authentication types), the TLS library wrapper should maintain a reference + * counter and do global initialization only when moving from 0 to 1 reference. + */ +void * tls_init(void); + +/** + * tls_deinit - Deinitialize TLS library + * @tls_ctx: TLS context data from tls_init() + * + * Called once during program shutdown and once for each RSN pre-authentication + * session. If global library deinitialization is needed (i.e., one that is + * shared between both authentication types), the TLS library wrapper should + * maintain a reference counter and do global deinitialization only when moving + * from 1 to 0 references. + */ +void tls_deinit(void *tls_ctx); + +/** + * tls_get_errors - Process pending errors + * @tls_ctx: TLS context data from tls_init() + * Returns: Number of found error, 0 if no errors detected. + * + * Process all pending TLS errors. + */ +int tls_get_errors(void *tls_ctx); + +/** + * tls_connection_init - Initialize a new TLS connection + * @tls_ctx: TLS context data from tls_init() + * Returns: Connection context data, conn for other function calls + */ +struct tls_connection * tls_connection_init(void *tls_ctx); + +/** + * tls_connection_deinit - Free TLS connection data + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * + * Release all resources allocated for TLS connection. + */ +void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn); + +/** + * tls_connection_established - Has the TLS connection been completed? + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * Returns: 1 if TLS connection has been completed, 0 if not. + */ +int tls_connection_established(void *tls_ctx, struct tls_connection *conn); + +/** + * tls_connection_shutdown - Shutdown TLS connection + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * Returns: 0 on success, -1 on failure + * + * Shutdown current TLS connection without releasing all resources. New + * connection can be started by using the same conn without having to call + * tls_connection_init() or setting certificates etc. again. The new + * connection should try to use session resumption. + */ +int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn); + +enum { + TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3, + TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2 +}; + +/** + * tls_connection_set_params - Set TLS connection parameters + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @params: Connection parameters + * Returns: 0 on success, -1 on failure, + * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing + * PKCS#11 engine failure, or + * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the + * PKCS#11 engine private key. + */ +int __must_check +tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, + const struct tls_connection_params *params); + +/** + * tls_global_set_params - Set TLS parameters for all TLS connection + * @tls_ctx: TLS context data from tls_init() + * @params: Global TLS parameters + * Returns: 0 on success, -1 on failure, + * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing + * PKCS#11 engine failure, or + * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the + * PKCS#11 engine private key. + */ +int __must_check tls_global_set_params( + void *tls_ctx, const struct tls_connection_params *params); + +/** + * tls_global_set_verify - Set global certificate verification options + * @tls_ctx: TLS context data from tls_init() + * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate, + * 2 = verify CRL for all certificates + * Returns: 0 on success, -1 on failure + */ +int __must_check tls_global_set_verify(void *tls_ctx, int check_crl); + +/** + * tls_connection_set_verify - Set certificate verification options + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @verify_peer: 1 = verify peer certificate + * Returns: 0 on success, -1 on failure + */ +int __must_check tls_connection_set_verify(void *tls_ctx, + struct tls_connection *conn, + int verify_peer); + +/** + * tls_connection_get_keys - Get master key and random data from TLS connection + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @keys: Structure of key/random data (filled on success) + * Returns: 0 on success, -1 on failure + */ +int __must_check tls_connection_get_keys(void *tls_ctx, + struct tls_connection *conn, + struct tls_keys *keys); + +/** + * tls_connection_prf - Use TLS-PRF to derive keying material + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @label: Label (e.g., description of the key) for PRF + * @server_random_first: seed is 0 = client_random|server_random, + * 1 = server_random|client_random + * @out: Buffer for output data from TLS-PRF + * @out_len: Length of the output buffer + * Returns: 0 on success, -1 on failure + * + * This function is optional to implement if tls_connection_get_keys() provides + * access to master secret and server/client random values. If these values are + * not exported from the TLS library, tls_connection_prf() is required so that + * further keying material can be derived from the master secret. If not + * implemented, the function will still need to be defined, but it can just + * return -1. Example implementation of this function is in tls_prf_sha1_md5() + * when it is called with seed set to client_random|server_random (or + * server_random|client_random). + */ +int __must_check tls_connection_prf(void *tls_ctx, + struct tls_connection *conn, + const char *label, + int server_random_first, + u8 *out, size_t out_len); + +/** + * tls_connection_handshake - Process TLS handshake (client side) + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @in_data: Input data from TLS server + * @appl_data: Pointer to application data pointer, or %NULL if dropped + * Returns: Output data, %NULL on failure + * + * The caller is responsible for freeing the returned output data. If the final + * handshake message includes application data, this is decrypted and + * appl_data (if not %NULL) is set to point this data. The caller is + * responsible for freeing appl_data. + * + * This function is used during TLS handshake. The first call is done with + * in_data == %NULL and the library is expected to return ClientHello packet. + * This packet is then send to the server and a response from server is given + * to TLS library by calling this function again with in_data pointing to the + * TLS message from the server. + * + * If the TLS handshake fails, this function may return %NULL. However, if the + * TLS library has a TLS alert to send out, that should be returned as the + * output data. In this case, tls_connection_get_failed() must return failure + * (> 0). + * + * tls_connection_established() should return 1 once the TLS handshake has been + * completed successfully. + */ +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data); + +struct wpabuf * tls_connection_handshake2(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data, + int *more_data_needed); + +/** + * tls_connection_server_handshake - Process TLS handshake (server side) + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @in_data: Input data from TLS peer + * @appl_data: Pointer to application data pointer, or %NULL if dropped + * Returns: Output data, %NULL on failure + * + * The caller is responsible for freeing the returned output data. + */ +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data); + +/** + * tls_connection_encrypt - Encrypt data into TLS tunnel + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @in_data: Plaintext data to be encrypted + * Returns: Encrypted TLS data or %NULL on failure + * + * This function is used after TLS handshake has been completed successfully to + * send data in the encrypted tunnel. The caller is responsible for freeing the + * returned output data. + */ +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data); + +/** + * tls_connection_decrypt - Decrypt data from TLS tunnel + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @in_data: Encrypted TLS data + * Returns: Decrypted TLS data or %NULL on failure + * + * This function is used after TLS handshake has been completed successfully to + * receive data from the encrypted tunnel. The caller is responsible for + * freeing the returned output data. + */ +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data); + +struct wpabuf * tls_connection_decrypt2(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + int *more_data_needed); + +/** + * tls_connection_resumed - Was session resumption used + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * Returns: 1 if current session used session resumption, 0 if not + */ +int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn); + +enum { + TLS_CIPHER_NONE, + TLS_CIPHER_RC4_SHA /* 0x0005 */, + TLS_CIPHER_AES128_SHA /* 0x002f */, + TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */, + TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */ +}; + +/** + * tls_connection_set_cipher_list - Configure acceptable cipher suites + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers + * (TLS_CIPHER_*). + * Returns: 0 on success, -1 on failure + */ +int __must_check tls_connection_set_cipher_list(void *tls_ctx, + struct tls_connection *conn, + u8 *ciphers); + +/** + * tls_get_cipher - Get current cipher name + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @buf: Buffer for the cipher name + * @buflen: buf size + * Returns: 0 on success, -1 on failure + * + * Get the name of the currently used cipher. + */ +int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn, + char *buf, size_t buflen); + +/** + * tls_connection_enable_workaround - Enable TLS workaround options + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * Returns: 0 on success, -1 on failure + * + * This function is used to enable connection-specific workaround options for + * buffer SSL/TLS implementations. + */ +int __must_check tls_connection_enable_workaround(void *tls_ctx, + struct tls_connection *conn); + +/** + * tls_connection_client_hello_ext - Set TLS extension for ClientHello + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * @ext_type: Extension type + * @data: Extension payload (%NULL to remove extension) + * @data_len: Extension payload length + * Returns: 0 on success, -1 on failure + */ +int __must_check tls_connection_client_hello_ext(void *tls_ctx, + struct tls_connection *conn, + int ext_type, const u8 *data, + size_t data_len); + +/** + * tls_connection_get_failed - Get connection failure status + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * + * Returns >0 if connection has failed, 0 if not. + */ +int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn); + +/** + * tls_connection_get_read_alerts - Get connection read alert status + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * Returns: Number of times a fatal read (remote end reported error) has + * happened during this connection. + */ +int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn); + +/** + * tls_connection_get_write_alerts - Get connection write alert status + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * Returns: Number of times a fatal write (locally detected error) has happened + * during this connection. + */ +int tls_connection_get_write_alerts(void *tls_ctx, + struct tls_connection *conn); + +/** + * tls_connection_get_keyblock_size - Get TLS key_block size + * @tls_ctx: TLS context data from tls_init() + * @conn: Connection context data from tls_connection_init() + * Returns: Size of the key_block for the negotiated cipher suite or -1 on + * failure + */ +int tls_connection_get_keyblock_size(void *tls_ctx, + struct tls_connection *conn); + +/** + * tls_capabilities - Get supported TLS capabilities + * @tls_ctx: TLS context data from tls_init() + * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*) + */ +unsigned int tls_capabilities(void *tls_ctx); + +typedef int (*tls_session_ticket_cb) +(void *ctx, const u8 *ticket, size_t len, const u8 *client_random, + const u8 *server_random, u8 *master_secret); + +int __must_check tls_connection_set_session_ticket_cb( + void *tls_ctx, struct tls_connection *conn, + tls_session_ticket_cb cb, void *ctx); + +int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label, + const u8 *seed, size_t seed_len, u8 *out, size_t outlen); + +#endif /* TLS_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_client.h b/components/wpa_supplicant/include/wpa2/tls/tlsv1_client.h new file mode 100644 index 0000000000..8ec85f1a91 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/tlsv1_client.h @@ -0,0 +1,54 @@ +/* + * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) + * Copyright (c) 2006-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef TLSV1_CLIENT_H +#define TLSV1_CLIENT_H + +#include "tlsv1_cred.h" + +struct tlsv1_client; + +int tlsv1_client_global_init(void); +void tlsv1_client_global_deinit(void); +struct tlsv1_client * tlsv1_client_init(void); +void tlsv1_client_deinit(struct tlsv1_client *conn); +int tlsv1_client_established(struct tlsv1_client *conn); +int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, + int server_random_first, u8 *out, size_t out_len); +u8 * tlsv1_client_handshake(struct tlsv1_client *conn, + const u8 *in_data, size_t in_len, + size_t *out_len, u8 **appl_data, + size_t *appl_data_len, int *need_more_data); +int tlsv1_client_encrypt(struct tlsv1_client *conn, + const u8 *in_data, size_t in_len, + u8 *out_data, size_t out_len); +struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn, + const u8 *in_data, size_t in_len, + int *need_more_data); +int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, + size_t buflen); +int tlsv1_client_shutdown(struct tlsv1_client *conn); +int tlsv1_client_resumed(struct tlsv1_client *conn); +int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type, + const u8 *data, size_t data_len); +int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys); +int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn); +int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers); +int tlsv1_client_set_cred(struct tlsv1_client *conn, + struct tlsv1_credentials *cred); +void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled); + +typedef int (*tlsv1_client_session_ticket_cb) +(void *ctx, const u8 *ticket, size_t len, const u8 *client_random, + const u8 *server_random, u8 *master_secret); + +void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn, + tlsv1_client_session_ticket_cb cb, + void *ctx); + +#endif /* TLSV1_CLIENT_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_client_i.h b/components/wpa_supplicant/include/wpa2/tls/tlsv1_client_i.h new file mode 100644 index 0000000000..55fdcf8d04 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/tlsv1_client_i.h @@ -0,0 +1,84 @@ +/* + * TLSv1 client - internal structures + * Copyright (c) 2006-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef TLSV1_CLIENT_I_H +#define TLSV1_CLIENT_I_H + +struct tlsv1_client { + enum { + CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE, + SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST, + SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC, + SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED, + ESTABLISHED, FAILED + } state; + + struct tlsv1_record_layer rl; + + u8 session_id[TLS_SESSION_ID_MAX_LEN]; + size_t session_id_len; + u8 client_random[TLS_RANDOM_LEN]; + u8 server_random[TLS_RANDOM_LEN]; + u8 master_secret[TLS_MASTER_SECRET_LEN]; + + u8 alert_level; + u8 alert_description; + + unsigned int certificate_requested:1; + unsigned int session_resumed:1; + unsigned int session_ticket_included:1; + unsigned int use_session_ticket:1; + unsigned int disable_time_checks:1; + + struct crypto_public_key *server_rsa_key; + + struct tls_verify_hash verify; + +#define MAX_CIPHER_COUNT 30 + u16 cipher_suites[MAX_CIPHER_COUNT]; + size_t num_cipher_suites; + + u16 prev_cipher_suite; + + u8 *client_hello_ext; + size_t client_hello_ext_len; + + /* The prime modulus used for Diffie-Hellman */ + u8 *dh_p; + size_t dh_p_len; + /* The generator used for Diffie-Hellman */ + u8 *dh_g; + size_t dh_g_len; + /* The server's Diffie-Hellman public value */ + u8 *dh_ys; + size_t dh_ys_len; + + struct tlsv1_credentials *cred; + + tlsv1_client_session_ticket_cb session_ticket_cb; + void *session_ticket_cb_ctx; + + struct wpabuf *partial_input; +}; + + +void tls_alert(struct tlsv1_client *conn, u8 level, u8 description); +void tlsv1_client_free_dh(struct tlsv1_client *conn); +int tls_derive_pre_master_secret(u8 *pre_master_secret); +int tls_derive_keys(struct tlsv1_client *conn, + const u8 *pre_master_secret, size_t pre_master_secret_len); +u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len); +u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, + u8 description, size_t *out_len); +u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, + int no_appl_data); +int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, + const u8 *buf, size_t *len, + u8 **out_data, size_t *out_len); + +#endif /* TLSV1_CLIENT_I_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_common.h b/components/wpa_supplicant/include/wpa2/tls/tlsv1_common.h new file mode 100644 index 0000000000..f28c0cdc47 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/tlsv1_common.h @@ -0,0 +1,261 @@ +/* + * TLSv1 common definitions + * Copyright (c) 2006-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef TLSV1_COMMON_H +#define TLSV1_COMMON_H + +#include "crypto/crypto.h" + +#define TLS_VERSION_1 0x0301 /* TLSv1 */ +#define TLS_VERSION_1_1 0x0302 /* TLSv1.1 */ +#define TLS_VERSION_1_2 0x0303 /* TLSv1.2 */ +#ifdef CONFIG_TLSV12 +#define TLS_VERSION TLS_VERSION_1_2 +#else /* CONFIG_TLSV12 */ +#ifdef CONFIG_TLSV11 +#define TLS_VERSION TLS_VERSION_1_1 +#else /* CONFIG_TLSV11 */ +#define TLS_VERSION TLS_VERSION_1 +#endif /* CONFIG_TLSV11 */ +#endif /* CONFIG_TLSV12 */ +#define TLS_RANDOM_LEN 32 +#define TLS_PRE_MASTER_SECRET_LEN 48 +#define TLS_MASTER_SECRET_LEN 48 +#define TLS_SESSION_ID_MAX_LEN 32 +#define TLS_VERIFY_DATA_LEN 12 + +/* HandshakeType */ +enum { + TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0, + TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1, + TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2, + TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */, + TLS_HANDSHAKE_TYPE_CERTIFICATE = 11, + TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12, + TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13, + TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14, + TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15, + TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16, + TLS_HANDSHAKE_TYPE_FINISHED = 20, + TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */, + TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */ +}; + +/* CipherSuite */ +#define TLS_NULL_WITH_NULL_NULL 0x0000 /* RFC 2246 */ +#define TLS_RSA_WITH_NULL_MD5 0x0001 /* RFC 2246 */ +#define TLS_RSA_WITH_NULL_SHA 0x0002 /* RFC 2246 */ +#define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003 /* RFC 2246 */ +#define TLS_RSA_WITH_RC4_128_MD5 0x0004 /* RFC 2246 */ +#define TLS_RSA_WITH_RC4_128_SHA 0x0005 /* RFC 2246 */ +#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006 /* RFC 2246 */ +#define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 /* RFC 2246 */ +#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008 /* RFC 2246 */ +#define TLS_RSA_WITH_DES_CBC_SHA 0x0009 /* RFC 2246 */ +#define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A /* RFC 2246 */ +#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000B /* RFC 2246 */ +#define TLS_DH_DSS_WITH_DES_CBC_SHA 0x000C /* RFC 2246 */ +#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D /* RFC 2246 */ +#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000E /* RFC 2246 */ +#define TLS_DH_RSA_WITH_DES_CBC_SHA 0x000F /* RFC 2246 */ +#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 /* RFC 2246 */ +#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011 /* RFC 2246 */ +#define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x0012 /* RFC 2246 */ +#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 /* RFC 2246 */ +#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014 /* RFC 2246 */ +#define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x0015 /* RFC 2246 */ +#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 /* RFC 2246 */ +#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 0x0017 /* RFC 2246 */ +#define TLS_DH_anon_WITH_RC4_128_MD5 0x0018 /* RFC 2246 */ +#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA 0x0019 /* RFC 2246 */ +#define TLS_DH_anon_WITH_DES_CBC_SHA 0x001A /* RFC 2246 */ +#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B /* RFC 2246 */ +#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F /* RFC 3268 */ +#define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 /* RFC 3268 */ +#define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 /* RFC 3268 */ +#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 /* RFC 3268 */ +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 /* RFC 3268 */ +#define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 /* RFC 3268 */ +#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 /* RFC 3268 */ +#define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 /* RFC 3268 */ +#define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 /* RFC 3268 */ +#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 /* RFC 3268 */ +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* RFC 3268 */ +#define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* RFC 3268 */ +#define TLS_RSA_WITH_NULL_SHA256 0x003B /* RFC 5246 */ +#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C /* RFC 5246 */ +#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D /* RFC 5246 */ +#define TLS_DH_DSS_WITH_AES_128_CBC_SHA256 0x003E /* RFC 5246 */ +#define TLS_DH_RSA_WITH_AES_128_CBC_SHA256 0x003F /* RFC 5246 */ +#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040 /* RFC 5246 */ +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067 /* RFC 5246 */ +#define TLS_DH_DSS_WITH_AES_256_CBC_SHA256 0x0068 /* RFC 5246 */ +#define TLS_DH_RSA_WITH_AES_256_CBC_SHA256 0x0069 /* RFC 5246 */ +#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A /* RFC 5246 */ +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B /* RFC 5246 */ +#define TLS_DH_anon_WITH_AES_128_CBC_SHA256 0x006C /* RFC 5246 */ +#define TLS_DH_anon_WITH_AES_256_CBC_SHA256 0x006D /* RFC 5246 */ + +/* CompressionMethod */ +#define TLS_COMPRESSION_NULL 0 + +/* HashAlgorithm */ +enum { + TLS_HASH_ALG_NONE = 0, + TLS_HASH_ALG_MD5 = 1, + TLS_HASH_ALG_SHA1 = 2, + TLS_HASH_ALG_SHA224 = 3, + TLS_HASH_ALG_SHA256 = 4, + TLS_HASH_ALG_SHA384 = 5, + TLS_HASH_ALG_SHA512 = 6 +}; + +/* SignatureAlgorithm */ +enum { + TLS_SIGN_ALG_ANONYMOUS = 0, + TLS_SIGN_ALG_RSA = 1, + TLS_SIGN_ALG_DSA = 2, + TLS_SIGN_ALG_ECDSA = 3, +}; + +/* AlertLevel */ +#define TLS_ALERT_LEVEL_WARNING 1 +#define TLS_ALERT_LEVEL_FATAL 2 + +/* AlertDescription */ +#define TLS_ALERT_CLOSE_NOTIFY 0 +#define TLS_ALERT_UNEXPECTED_MESSAGE 10 +#define TLS_ALERT_BAD_RECORD_MAC 20 +#define TLS_ALERT_DECRYPTION_FAILED 21 +#define TLS_ALERT_RECORD_OVERFLOW 22 +#define TLS_ALERT_DECOMPRESSION_FAILURE 30 +#define TLS_ALERT_HANDSHAKE_FAILURE 40 +#define TLS_ALERT_BAD_CERTIFICATE 42 +#define TLS_ALERT_UNSUPPORTED_CERTIFICATE 43 +#define TLS_ALERT_CERTIFICATE_REVOKED 44 +#define TLS_ALERT_CERTIFICATE_EXPIRED 45 +#define TLS_ALERT_CERTIFICATE_UNKNOWN 46 +#define TLS_ALERT_ILLEGAL_PARAMETER 47 +#define TLS_ALERT_UNKNOWN_CA 48 +#define TLS_ALERT_ACCESS_DENIED 49 +#define TLS_ALERT_DECODE_ERROR 50 +#define TLS_ALERT_DECRYPT_ERROR 51 +#define TLS_ALERT_EXPORT_RESTRICTION 60 +#define TLS_ALERT_PROTOCOL_VERSION 70 +#define TLS_ALERT_INSUFFICIENT_SECURITY 71 +#define TLS_ALERT_INTERNAL_ERROR 80 +#define TLS_ALERT_USER_CANCELED 90 +#define TLS_ALERT_NO_RENEGOTIATION 100 +#define TLS_ALERT_UNSUPPORTED_EXTENSION 110 /* RFC 4366 */ +#define TLS_ALERT_CERTIFICATE_UNOBTAINABLE 111 /* RFC 4366 */ +#define TLS_ALERT_UNRECOGNIZED_NAME 112 /* RFC 4366 */ +#define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE 113 /* RFC 4366 */ +#define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE 114 /* RFC 4366 */ + +/* ChangeCipherSpec */ +enum { + TLS_CHANGE_CIPHER_SPEC = 1 +}; + +/* TLS Extensions */ +#define TLS_EXT_SERVER_NAME 0 /* RFC 4366 */ +#define TLS_EXT_MAX_FRAGMENT_LENGTH 1 /* RFC 4366 */ +#define TLS_EXT_CLIENT_CERTIFICATE_URL 2 /* RFC 4366 */ +#define TLS_EXT_TRUSTED_CA_KEYS 3 /* RFC 4366 */ +#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */ +#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */ +#define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */ + +#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */ + + +typedef enum { + TLS_KEY_X_NULL, + TLS_KEY_X_RSA, + TLS_KEY_X_RSA_EXPORT, + TLS_KEY_X_DH_DSS_EXPORT, + TLS_KEY_X_DH_DSS, + TLS_KEY_X_DH_RSA_EXPORT, + TLS_KEY_X_DH_RSA, + TLS_KEY_X_DHE_DSS_EXPORT, + TLS_KEY_X_DHE_DSS, + TLS_KEY_X_DHE_RSA_EXPORT, + TLS_KEY_X_DHE_RSA, + TLS_KEY_X_DH_anon_EXPORT, + TLS_KEY_X_DH_anon +} tls_key_exchange; + +typedef enum { + TLS_CIPHER_NULL, + TLS_CIPHER_RC4_40, + TLS_CIPHER_RC4_128, + TLS_CIPHER_RC2_CBC_40, + TLS_CIPHER_IDEA_CBC, + TLS_CIPHER_DES40_CBC, + TLS_CIPHER_DES_CBC, + TLS_CIPHER_3DES_EDE_CBC, + TLS_CIPHER_AES_128_CBC, + TLS_CIPHER_AES_256_CBC +} tls_cipher; + +typedef enum { + TLS_HASH_NULL, + TLS_HASH_MD5, + TLS_HASH_SHA, + TLS_HASH_SHA256 +} tls_hash; + +struct tls_cipher_suite { + u16 suite; + tls_key_exchange key_exchange; + tls_cipher cipher; + tls_hash hash; +}; + +typedef enum { + TLS_CIPHER_STREAM, + TLS_CIPHER_BLOCK +} tls_cipher_type; + +struct tls_cipher_data { + tls_cipher cipher; + tls_cipher_type type; + size_t key_material; + size_t expanded_key_material; + size_t block_size; /* also iv_size */ + enum crypto_cipher_alg alg; +}; + + +struct tls_verify_hash { + struct crypto_hash *md5_client; + struct crypto_hash *sha1_client; + struct crypto_hash *sha256_client; + struct crypto_hash *md5_server; + struct crypto_hash *sha1_server; + struct crypto_hash *sha256_server; + struct crypto_hash *md5_cert; + struct crypto_hash *sha1_cert; + struct crypto_hash *sha256_cert; +}; + + +const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite); +const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher); +int tls_server_key_exchange_allowed(tls_cipher cipher); +int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk); +int tls_verify_hash_init(struct tls_verify_hash *verify); +void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, + size_t len); +void tls_verify_hash_free(struct tls_verify_hash *verify); +int tls_version_ok(u16 ver); +const char * tls_version_str(u16 ver); +int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label, + const u8 *seed, size_t seed_len, u8 *out, size_t outlen); + +#endif /* TLSV1_COMMON_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_cred.h b/components/wpa_supplicant/include/wpa2/tls/tlsv1_cred.h new file mode 100644 index 0000000000..68fbdc9230 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/tlsv1_cred.h @@ -0,0 +1,40 @@ +/* + * TLSv1 credentials + * Copyright (c) 2006-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef TLSV1_CRED_H +#define TLSV1_CRED_H + +struct tlsv1_credentials { + struct x509_certificate *trusted_certs; + struct x509_certificate *cert; + struct crypto_private_key *key; + + /* Diffie-Hellman parameters */ + u8 *dh_p; /* prime */ + size_t dh_p_len; + u8 *dh_g; /* generator */ + size_t dh_g_len; +}; + + +struct tlsv1_credentials * tlsv1_cred_alloc(void); +void tlsv1_cred_free(struct tlsv1_credentials *cred); +int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert, + const u8 *cert_blob, size_t cert_blob_len, + const char *path); +int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, + const u8 *cert_blob, size_t cert_blob_len); +int tlsv1_set_private_key(struct tlsv1_credentials *cred, + const char *private_key, + const char *private_key_passwd, + const u8 *private_key_blob, + size_t private_key_blob_len); +int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, + const u8 *dh_blob, size_t dh_blob_len); + +#endif /* TLSV1_CRED_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_record.h b/components/wpa_supplicant/include/wpa2/tls/tlsv1_record.h new file mode 100644 index 0000000000..48abcb0d25 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/tlsv1_record.h @@ -0,0 +1,71 @@ +/* + * TLSv1 Record Protocol + * Copyright (c) 2006-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef TLSV1_RECORD_H +#define TLSV1_RECORD_H + +#include "crypto/crypto.h" + +#define TLS_MAX_WRITE_MAC_SECRET_LEN 32 +#define TLS_MAX_WRITE_KEY_LEN 32 +#define TLS_MAX_IV_LEN 16 +#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \ + TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN)) + +#define TLS_SEQ_NUM_LEN 8 +#define TLS_RECORD_HEADER_LEN 5 + +/* ContentType */ +enum { + TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20, + TLS_CONTENT_TYPE_ALERT = 21, + TLS_CONTENT_TYPE_HANDSHAKE = 22, + TLS_CONTENT_TYPE_APPLICATION_DATA = 23 +}; + +struct tlsv1_record_layer { + u16 tls_version; + + u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN]; + u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN]; + u8 write_key[TLS_MAX_WRITE_KEY_LEN]; + u8 read_key[TLS_MAX_WRITE_KEY_LEN]; + u8 write_iv[TLS_MAX_IV_LEN]; + u8 read_iv[TLS_MAX_IV_LEN]; + + size_t hash_size; + size_t key_material_len; + size_t iv_size; /* also block_size */ + + enum crypto_hash_alg hash_alg; + enum crypto_cipher_alg cipher_alg; + + u8 write_seq_num[TLS_SEQ_NUM_LEN]; + u8 read_seq_num[TLS_SEQ_NUM_LEN]; + + u16 cipher_suite; + u16 write_cipher_suite; + u16 read_cipher_suite; + + struct crypto_cipher *write_cbc; + struct crypto_cipher *read_cbc; +}; + + +int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, + u16 cipher_suite); +int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl); +int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl); +int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, + size_t buf_size, const u8 *payload, size_t payload_len, + size_t *out_len); +int tlsv1_record_receive(struct tlsv1_record_layer *rl, + const u8 *in_data, size_t in_len, + u8 *out_data, size_t *out_len, u8 *alert); + +#endif /* TLSV1_RECORD_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_server.h b/components/wpa_supplicant/include/wpa2/tls/tlsv1_server.h new file mode 100644 index 0000000000..a18c69e37c --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/tlsv1_server.h @@ -0,0 +1,48 @@ +/* + * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246) + * Copyright (c) 2006-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef TLSV1_SERVER_H +#define TLSV1_SERVER_H + +#include "tlsv1_cred.h" + +struct tlsv1_server; + +int tlsv1_server_global_init(void); +void tlsv1_server_global_deinit(void); +struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred); +void tlsv1_server_deinit(struct tlsv1_server *conn); +int tlsv1_server_established(struct tlsv1_server *conn); +int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, + int server_random_first, u8 *out, size_t out_len); +u8 * tlsv1_server_handshake(struct tlsv1_server *conn, + const u8 *in_data, size_t in_len, size_t *out_len); +int tlsv1_server_encrypt(struct tlsv1_server *conn, + const u8 *in_data, size_t in_len, + u8 *out_data, size_t out_len); +int tlsv1_server_decrypt(struct tlsv1_server *conn, + const u8 *in_data, size_t in_len, + u8 *out_data, size_t out_len); +int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf, + size_t buflen); +int tlsv1_server_shutdown(struct tlsv1_server *conn); +int tlsv1_server_resumed(struct tlsv1_server *conn); +int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys); +int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn); +int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers); +int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer); + +typedef int (*tlsv1_server_session_ticket_cb) +(void *ctx, const u8 *ticket, size_t len, const u8 *client_random, + const u8 *server_random, u8 *master_secret); + +void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn, + tlsv1_server_session_ticket_cb cb, + void *ctx); + +#endif /* TLSV1_SERVER_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/tlsv1_server_i.h b/components/wpa_supplicant/include/wpa2/tls/tlsv1_server_i.h new file mode 100644 index 0000000000..1f61533a5a --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/tlsv1_server_i.h @@ -0,0 +1,71 @@ +/* + * TLSv1 server - internal structures + * Copyright (c) 2006-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef TLSV1_SERVER_I_H +#define TLSV1_SERVER_I_H + +struct tlsv1_server { + enum { + CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE, + SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST, + SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE, + CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED, + SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, + ESTABLISHED, FAILED + } state; + + struct tlsv1_record_layer rl; + + u8 session_id[TLS_SESSION_ID_MAX_LEN]; + size_t session_id_len; + u8 client_random[TLS_RANDOM_LEN]; + u8 server_random[TLS_RANDOM_LEN]; + u8 master_secret[TLS_MASTER_SECRET_LEN]; + + u8 alert_level; + u8 alert_description; + + struct crypto_public_key *client_rsa_key; + + struct tls_verify_hash verify; + +#define MAX_CIPHER_COUNT 30 + u16 cipher_suites[MAX_CIPHER_COUNT]; + size_t num_cipher_suites; + + u16 cipher_suite; + + struct tlsv1_credentials *cred; + + int verify_peer; + u16 client_version; + + u8 *session_ticket; + size_t session_ticket_len; + + tlsv1_server_session_ticket_cb session_ticket_cb; + void *session_ticket_cb_ctx; + + int use_session_ticket; + + u8 *dh_secret; + size_t dh_secret_len; +}; + + +void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description); +int tlsv1_server_derive_keys(struct tlsv1_server *conn, + const u8 *pre_master_secret, + size_t pre_master_secret_len); +u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len); +u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, + u8 description, size_t *out_len); +int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, + const u8 *buf, size_t *len); + +#endif /* TLSV1_SERVER_I_H */ diff --git a/components/wpa_supplicant/include/wpa2/tls/x509v3.h b/components/wpa_supplicant/include/wpa2/tls/x509v3.h new file mode 100644 index 0000000000..91a35baf92 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/tls/x509v3.h @@ -0,0 +1,123 @@ +/* + * X.509v3 certificate parsing and processing + * Copyright (c) 2006-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef X509V3_H +#define X509V3_H + +#include "asn1.h" + +struct x509_algorithm_identifier { + struct asn1_oid oid; +}; + +struct x509_name_attr { + enum x509_name_attr_type { + X509_NAME_ATTR_NOT_USED, + X509_NAME_ATTR_DC, + X509_NAME_ATTR_CN, + X509_NAME_ATTR_C, + X509_NAME_ATTR_L, + X509_NAME_ATTR_ST, + X509_NAME_ATTR_O, + X509_NAME_ATTR_OU + } type; + char *value; +}; + +#define X509_MAX_NAME_ATTRIBUTES 20 + +struct x509_name { + struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES]; + size_t num_attr; + char *email; /* emailAddress */ + + /* from alternative name extension */ + char *alt_email; /* rfc822Name */ + char *dns; /* dNSName */ + char *uri; /* uniformResourceIdentifier */ + u8 *ip; /* iPAddress */ + size_t ip_len; /* IPv4: 4, IPv6: 16 */ + struct asn1_oid rid; /* registeredID */ +}; + +struct x509_certificate { + struct x509_certificate *next; + enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version; + unsigned long serial_number; + struct x509_algorithm_identifier signature; + struct x509_name issuer; + struct x509_name subject; + os_time_t not_before; + os_time_t not_after; + struct x509_algorithm_identifier public_key_alg; + u8 *public_key; + size_t public_key_len; + struct x509_algorithm_identifier signature_alg; + u8 *sign_value; + size_t sign_value_len; + + /* Extensions */ + unsigned int extensions_present; +#define X509_EXT_BASIC_CONSTRAINTS (1 << 0) +#define X509_EXT_PATH_LEN_CONSTRAINT (1 << 1) +#define X509_EXT_KEY_USAGE (1 << 2) +#define X509_EXT_SUBJECT_ALT_NAME (1 << 3) +#define X509_EXT_ISSUER_ALT_NAME (1 << 4) + + /* BasicConstraints */ + int ca; /* cA */ + unsigned long path_len_constraint; /* pathLenConstraint */ + + /* KeyUsage */ + unsigned long key_usage; +#define X509_KEY_USAGE_DIGITAL_SIGNATURE (1 << 0) +#define X509_KEY_USAGE_NON_REPUDIATION (1 << 1) +#define X509_KEY_USAGE_KEY_ENCIPHERMENT (1 << 2) +#define X509_KEY_USAGE_DATA_ENCIPHERMENT (1 << 3) +#define X509_KEY_USAGE_KEY_AGREEMENT (1 << 4) +#define X509_KEY_USAGE_KEY_CERT_SIGN (1 << 5) +#define X509_KEY_USAGE_CRL_SIGN (1 << 6) +#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7) +#define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8) + + /* + * The DER format certificate follows struct x509_certificate. These + * pointers point to that buffer. + */ + const u8 *cert_start; + size_t cert_len; + const u8 *tbs_cert_start; + size_t tbs_cert_len; +}; + +enum { + X509_VALIDATE_OK, + X509_VALIDATE_BAD_CERTIFICATE, + X509_VALIDATE_UNSUPPORTED_CERTIFICATE, + X509_VALIDATE_CERTIFICATE_REVOKED, + X509_VALIDATE_CERTIFICATE_EXPIRED, + X509_VALIDATE_CERTIFICATE_UNKNOWN, + X509_VALIDATE_UNKNOWN_CA +}; + +void x509_certificate_free(struct x509_certificate *cert); +struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len); +void x509_name_string(struct x509_name *name, char *buf, size_t len); +int x509_name_compare(struct x509_name *a, struct x509_name *b); +void x509_certificate_chain_free(struct x509_certificate *cert); +int x509_certificate_check_signature(struct x509_certificate *issuer, + struct x509_certificate *cert); +int x509_certificate_chain_validate(struct x509_certificate *trusted, + struct x509_certificate *chain, + int *reason, int disable_time_checks); +struct x509_certificate * +x509_certificate_get_subject(struct x509_certificate *chain, + struct x509_name *name); +int x509_certificate_self_signed(struct x509_certificate *cert); + +#endif /* X509V3_H */ diff --git a/components/wpa_supplicant/include/wpa2/utils/base64.h b/components/wpa_supplicant/include/wpa2/utils/base64.h new file mode 100644 index 0000000000..91eb874198 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/utils/base64.h @@ -0,0 +1,17 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef BASE64_H +#define BASE64_H + +unsigned char * _base64_encode(const unsigned char *src, size_t len, + size_t *out_len); +unsigned char * _base64_decode(const unsigned char *src, size_t len, + size_t *out_len); + +#endif /* BASE64_H */ diff --git a/components/wpa_supplicant/include/wpa2/utils/ext_password.h b/components/wpa_supplicant/include/wpa2/utils/ext_password.h new file mode 100644 index 0000000000..e3e46ea084 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/utils/ext_password.h @@ -0,0 +1,33 @@ +/* + * External password backend + * Copyright (c) 2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EXT_PASSWORD_H +#define EXT_PASSWORD_H + +struct ext_password_data; + +#ifdef CONFIG_EXT_PASSWORD + +struct ext_password_data * ext_password_init(const char *backend, + const char *params); +void ext_password_deinit(struct ext_password_data *data); + +struct wpabuf * ext_password_get(struct ext_password_data *data, + const char *name); +void ext_password_free(struct wpabuf *pw); + +#else /* CONFIG_EXT_PASSWORD */ + +#define ext_password_init(b, p) ((void *) 1) +#define ext_password_deinit(d) do { } while (0) +#define ext_password_get(d, n) (NULL) +#define ext_password_free(p) do { } while (0) + +#endif /* CONFIG_EXT_PASSWORD */ + +#endif /* EXT_PASSWORD_H */ diff --git a/components/wpa_supplicant/include/wpa2/utils/ext_password_i.h b/components/wpa_supplicant/include/wpa2/utils/ext_password_i.h new file mode 100644 index 0000000000..043e7312c6 --- /dev/null +++ b/components/wpa_supplicant/include/wpa2/utils/ext_password_i.h @@ -0,0 +1,23 @@ +/* + * External password backend - internal definitions + * Copyright (c) 2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EXT_PASSWORD_I_H +#define EXT_PASSWORD_I_H + +#include "ext_password.h" + +struct ext_password_backend { + const char *name; + void * (*init)(const char *params); + void (*deinit)(void *ctx); + struct wpabuf * (*get)(void *ctx, const char *name); +}; + +struct wpabuf * ext_password_alloc(size_t len); + +#endif /* EXT_PASSWORD_I_H */ diff --git a/components/wpa_supplicant/port/include/byteswap.h b/components/wpa_supplicant/port/include/byteswap.h new file mode 100644 index 0000000000..1a8bb8fd15 --- /dev/null +++ b/components/wpa_supplicant/port/include/byteswap.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010 Espressif System + */ + +#ifndef BYTESWAP_H +#define BYTESWAP_H + +/* Swap bytes in 16 bit value. */ +#ifdef __GNUC__ +# define __bswap_16(x) \ + (__extension__ \ + ({ unsigned short int __bsx = (x); \ + ((((__bsx) >> 8) & 0xff) | (((__bsx) & 0xff) << 8)); })) +#else +static INLINE unsigned short int +__bswap_16 (unsigned short int __bsx) +{ + return ((((__bsx) >> 8) & 0xff) | (((__bsx) & 0xff) << 8)); +} +#endif + +/* Swap bytes in 32 bit value. */ +#ifdef __GNUC__ +# define __bswap_32(x) \ + (__extension__ \ + ({ unsigned int __bsx = (x); \ + ((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >> 8) | \ + (((__bsx) & 0x0000ff00) << 8) | (((__bsx) & 0x000000ff) << 24)); })) +#else +static INLINE unsigned int +__bswap_32 (unsigned int __bsx) +{ + return ((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >> 8) | + (((__bsx) & 0x0000ff00) << 8) | (((__bsx) & 0x000000ff) << 24)); +} +#endif + +#if defined __GNUC__ && __GNUC__ >= 2 +/* Swap bytes in 64 bit value. */ +# define __bswap_constant_64(x) \ + ((((x) & 0xff00000000000000ull) >> 56) \ + | (((x) & 0x00ff000000000000ull) >> 40) \ + | (((x) & 0x0000ff0000000000ull) >> 24) \ + | (((x) & 0x000000ff00000000ull) >> 8) \ + | (((x) & 0x00000000ff000000ull) << 8) \ + | (((x) & 0x0000000000ff0000ull) << 24) \ + | (((x) & 0x000000000000ff00ull) << 40) \ + | (((x) & 0x00000000000000ffull) << 56)) + +# define __bswap_64(x) \ + (__extension__ \ + ({ union { __extension__ unsigned long long int __ll; \ + unsigned int __l[2]; } __w, __r; \ + if (__builtin_constant_p (x)) \ + __r.__ll = __bswap_constant_64 (x); \ + else \ + { \ + __w.__ll = (x); \ + __r.__l[0] = __bswap_32 (__w.__l[1]); \ + __r.__l[1] = __bswap_32 (__w.__l[0]); \ + } \ + __r.__ll; })) +#endif + +#endif /* BYTESWAP_H */ diff --git a/components/wpa_supplicant/port/include/endian.h b/components/wpa_supplicant/port/include/endian.h new file mode 100644 index 0000000000..e2df616b79 --- /dev/null +++ b/components/wpa_supplicant/port/include/endian.h @@ -0,0 +1,229 @@ +/*- + * Copyright (c) 2002 Thomas Moestl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _ENDIAN_H_ +#define _ENDIAN_H_ + +#include "byteswap.h" + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BYTE_ORDER +#ifdef __IEEE_LITTLE_ENDIAN +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN +#endif +#endif + +#define _UINT8_T_DECLARED +#ifndef _UINT8_T_DECLARED +typedef __uint8_t uint8_t; +#define _UINT8_T_DECLARED +#endif + +#define _UINT16_T_DECLARED +#ifndef _UINT16_T_DECLARED +typedef __uint16_t uint16_t; +#define _UINT16_T_DECLARED +#endif + +#define _UINT32_T_DECLARED +#ifndef _UINT32_T_DECLARED +typedef __uint32_t uint32_t; +#define _UINT32_T_DECLARED +#endif + +#define _UINT64_T_DECLARED +#ifndef _UINT64_T_DECLARED +typedef __uint64_t uint64_t; +#define _UINT64_T_DECLARED +#endif + +/* + * General byte order swapping functions. + */ +#define bswap16(x) __bswap16(x) +#define bswap32(x) __bswap32(x) +#define bswap64(x) __bswap64(x) + +/* + * Host to big endian, host to little endian, big endian to host, and little + * endian to host byte order functions as detailed in byteorder(9). + */ +#if 1 //BYTE_ORDER == _LITTLE_ENDIAN +#define __bswap16 __bswap_16 +#define __bswap32 __bswap_32 +#define htobe16(x) bswap16((x)) +#define htobe32(x) bswap32((x)) +#define htobe64(x) bswap64((x)) +#define htole16(x) ((uint16_t)(x)) +#define htole32(x) ((uint32_t)(x)) +#define htole64(x) ((uint64_t)(x)) + +#define be16toh(x) bswap16((x)) +#define be32toh(x) bswap32((x)) +#define be64toh(x) bswap64((x)) +#define le16toh(x) ((uint16_t)(x)) +#define le32toh(x) ((uint32_t)(x)) +#define le64toh(x) ((uint64_t)(x)) + +#ifndef htons +#define htons htobe16 +#endif //htons + +#else /* _BYTE_ORDER != _LITTLE_ENDIAN */ +#define htobe16(x) ((uint16_t)(x)) +#define htobe32(x) ((uint32_t)(x)) +#define htobe64(x) ((uint64_t)(x)) +#define htole16(x) bswap16((x)) +#define htole32(x) bswap32((x)) +#define htole64(x) bswap64((x)) + +#define be16toh(x) ((uint16_t)(x)) +#define be32toh(x) ((uint32_t)(x)) +#define be64toh(x) ((uint64_t)(x)) +#define le16toh(x) bswap16((x)) +#define le32toh(x) bswap32((x)) +#define le64toh(x) bswap64((x)) +#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */ + +/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */ + +static INLINE uint16_t +be16dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return ((p[0] << 8) | p[1]); +} + +static INLINE uint32_t +be32dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); +} + +static INLINE uint64_t +be64dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4)); +} + +static INLINE uint16_t +le16dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return ((p[1] << 8) | p[0]); +} + +static INLINE uint32_t +le32dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); +} + +static INLINE uint64_t +le64dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); +} + +static INLINE void +be16enc(void *pp, uint16_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = (u >> 8) & 0xff; + p[1] = u & 0xff; +} + +static INLINE void +be32enc(void *pp, uint32_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = (u >> 24) & 0xff; + p[1] = (u >> 16) & 0xff; + p[2] = (u >> 8) & 0xff; + p[3] = u & 0xff; +} + +static INLINE void +be64enc(void *pp, uint64_t u) +{ + uint8_t *p = (uint8_t *)pp; + + be32enc(p, (uint32_t)(u >> 32)); + be32enc(p + 4, (uint32_t)(u & 0xffffffffU)); +} + +static INLINE void +le16enc(void *pp, uint16_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; +} + +static INLINE void +le32enc(void *pp, uint32_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; + p[2] = (u >> 16) & 0xff; + p[3] = (u >> 24) & 0xff; +} + +static INLINE void +le64enc(void *pp, uint64_t u) +{ + uint8_t *p = (uint8_t *)pp; + + le32enc(p, (uint32_t)(u & 0xffffffffU)); + le32enc(p + 4, (uint32_t)(u >> 32)); +} + +#endif /* _ENDIAN_H_ */ diff --git a/components/wpa_supplicant/port/include/os.h b/components/wpa_supplicant/port/include/os.h new file mode 100644 index 0000000000..e6da894e92 --- /dev/null +++ b/components/wpa_supplicant/port/include/os.h @@ -0,0 +1,286 @@ +/* + * OS specific functions + * Copyright (c) 2005-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef OS_H +#define OS_H +#include "esp_types.h" +#include +#include +#include +#include "rom/ets_sys.h" +#include "lwip/mem.h" +typedef long os_time_t; + +/** + * os_sleep - Sleep (sec, usec) + * @sec: Number of seconds to sleep + * @usec: Number of microseconds to sleep + */ +void os_sleep(os_time_t sec, os_time_t usec); + +struct os_time { + os_time_t sec; + os_time_t usec; +}; + +/** + * os_get_time - Get current time (sec, usec) + * @t: Pointer to buffer for the time + * Returns: 0 on success, -1 on failure + */ +int os_get_time(struct os_time *t); + + +/* Helper macros for handling struct os_time */ + +#define os_time_before(a, b) \ + ((a)->sec < (b)->sec || \ + ((a)->sec == (b)->sec && (a)->usec < (b)->usec)) + +#define os_time_sub(a, b, res) do { \ + (res)->sec = (a)->sec - (b)->sec; \ + (res)->usec = (a)->usec - (b)->usec; \ + if ((res)->usec < 0) { \ + (res)->sec--; \ + (res)->usec += 1000000; \ + } \ +} while (0) + +/** + * os_mktime - Convert broken-down time into seconds since 1970-01-01 + * @year: Four digit year + * @month: Month (1 .. 12) + * @day: Day of month (1 .. 31) + * @hour: Hour (0 .. 23) + * @min: Minute (0 .. 59) + * @sec: Second (0 .. 60) + * @t: Buffer for returning calendar time representation (seconds since + * 1970-01-01 00:00:00) + * Returns: 0 on success, -1 on failure + * + * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time + * which is used by POSIX mktime(). + */ +int os_mktime(int year, int month, int day, int hour, int min, int sec, + os_time_t *t); + + +/** + * os_daemonize - Run in the background (detach from the controlling terminal) + * @pid_file: File name to write the process ID to or %NULL to skip this + * Returns: 0 on success, -1 on failure + */ +int os_daemonize(const char *pid_file); + +/** + * os_daemonize_terminate - Stop running in the background (remove pid file) + * @pid_file: File name to write the process ID to or %NULL to skip this + */ +void os_daemonize_terminate(const char *pid_file); + +/** + * os_get_random - Get cryptographically strong pseudo random data + * @buf: Buffer for pseudo random data + * @len: Length of the buffer + * Returns: 0 on success, -1 on failure + */ +int os_get_random(unsigned char *buf, size_t len); + +/** + * os_random - Get pseudo random value (not necessarily very strong) + * Returns: Pseudo random value + */ +unsigned long os_random(void); + +/** + * os_rel2abs_path - Get an absolute path for a file + * @rel_path: Relative path to a file + * Returns: Absolute path for the file or %NULL on failure + * + * This function tries to convert a relative path of a file to an absolute path + * in order for the file to be found even if current working directory has + * changed. The returned value is allocated and caller is responsible for + * freeing it. It is acceptable to just return the same path in an allocated + * buffer, e.g., return strdup(rel_path). This function is only used to find + * configuration files when os_daemonize() may have changed the current working + * directory and relative path would be pointing to a different location. + */ +char * os_rel2abs_path(const char *rel_path); + +/** + * os_program_init - Program initialization (called at start) + * Returns: 0 on success, -1 on failure + * + * This function is called when a programs starts. If there are any OS specific + * processing that is needed, it can be placed here. It is also acceptable to + * just return 0 if not special processing is needed. + */ +int os_program_init(void); + +/** + * os_program_deinit - Program deinitialization (called just before exit) + * + * This function is called just before a program exists. If there are any OS + * specific processing, e.g., freeing resourced allocated in os_program_init(), + * it should be done here. It is also acceptable for this function to do + * nothing. + */ +void os_program_deinit(void); + +/** + * os_setenv - Set environment variable + * @name: Name of the variable + * @value: Value to set to the variable + * @overwrite: Whether existing variable should be overwritten + * Returns: 0 on success, -1 on error + * + * This function is only used for wpa_cli action scripts. OS wrapper does not + * need to implement this if such functionality is not needed. + */ +int os_setenv(const char *name, const char *value, int overwrite); + +/** + * os_unsetenv - Delete environent variable + * @name: Name of the variable + * Returns: 0 on success, -1 on error + * + * This function is only used for wpa_cli action scripts. OS wrapper does not + * need to implement this if such functionality is not needed. + */ +int os_unsetenv(const char *name); + +/** + * os_readfile - Read a file to an allocated memory buffer + * @name: Name of the file to read + * @len: For returning the length of the allocated buffer + * Returns: Pointer to the allocated buffer or %NULL on failure + * + * This function allocates memory and reads the given file to this buffer. Both + * binary and text files can be read with this function. The caller is + * responsible for freeing the returned buffer with os_free(). + */ +char * os_readfile(const char *name, size_t *len); + +/* + * The following functions are wrapper for standard ANSI C or POSIX functions. + * By default, they are just defined to use the standard function name and no + * os_*.c implementation is needed for them. This avoids extra function calls + * by allowing the C pre-processor take care of the function name mapping. + * + * If the target system uses a C library that does not provide these functions, + * build_config.h can be used to define the wrappers to use a different + * function name. This can be done on function-by-function basis since the + * defines here are only used if build_config.h does not define the os_* name. + * If needed, os_*.c file can be used to implement the functions that are not + * included in the C library on the target system. Alternatively, + * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case + * these functions need to be implemented in os_*.c file for the target system. + */ + +#ifndef os_malloc +#define os_malloc(s) malloc((s)) +#endif +#ifndef os_realloc +#define os_realloc(p, s) realloc((p), (s)) +#endif +#ifndef os_zalloc +#define os_zalloc(s) calloc(1, (s)) +#endif +#ifndef os_free +#define os_free(p) free((p)) +#endif + + +#ifndef os_strdup +#ifdef _MSC_VER +#define os_strdup(s) _strdup(s) +#else +#define os_strdup(s) strdup(s) +#endif +#endif +char * ets_strdup(const char *s); + +#ifndef os_memcpy +#define os_memcpy(d, s, n) memcpy((d), (s), (n)) +#endif +#ifndef os_memmove +#define os_memmove(d, s, n) memmove((d), (s), (n)) +#endif +#ifndef os_memset +#define os_memset(s, c, n) memset(s, c, n) +#endif +#ifndef os_memcmp +#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) +#endif + +#ifndef os_strlen +#define os_strlen(s) strlen(s) +#endif +#ifndef os_strcasecmp +#ifdef _MSC_VER +#define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) +#else +#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2)) +#endif +#endif +#ifndef os_strncasecmp +#ifdef _MSC_VER +#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) +#else +#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n)) +#endif +#endif +#ifndef os_strchr +#define os_strchr(s, c) strchr((s), (c)) +#endif +#ifndef os_strcmp +#define os_strcmp(s1, s2) strcmp((s1), (s2)) +#endif +#ifndef os_strncmp +#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n)) +#endif +#ifndef os_strncpy +#define os_strncpy(d, s, n) strncpy((d), (s), (n)) +#endif +#ifndef os_strrchr +//hard cold +#define os_strrchr(s, c) NULL +#endif +#ifndef os_strstr +#define os_strstr(h, n) strstr((h), (n)) +#endif + +#ifndef os_snprintf +#ifdef _MSC_VER +#define os_snprintf _snprintf +#else +#define os_snprintf vsnprintf +#endif +#endif + +/** + * os_strlcpy - Copy a string with size bound and NUL-termination + * @dest: Destination + * @src: Source + * @siz: Size of the target buffer + * Returns: Total length of the target string (length of src) (not including + * NUL-termination) + * + * This function matches in behavior with the strlcpy(3) function in OpenBSD. + */ +size_t os_strlcpy(char *dest, const char *src, size_t siz); + + + +#endif /* OS_H */ diff --git a/components/wpa_supplicant/src/crypto/aes-cbc.c b/components/wpa_supplicant/src/crypto/aes-cbc.c new file mode 100644 index 0000000000..016207795e --- /dev/null +++ b/components/wpa_supplicant/src/crypto/aes-cbc.c @@ -0,0 +1,88 @@ +/* + * AES-128 CBC + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/aes.h" +#include "crypto/aes_wrap.h" + +/** + * aes_128_cbc_encrypt - AES-128 CBC encryption + * @key: Encryption key + * @iv: Encryption IV for CBC mode (16 bytes) + * @data: Data to encrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int +aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE]; + u8 *pos = data; + int i, j, blocks; + + ctx = aes_encrypt_init(key, 16); + if (ctx == NULL) + return -1; + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + + blocks = data_len / AES_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + for (j = 0; j < AES_BLOCK_SIZE; j++) + cbc[j] ^= pos[j]; + aes_encrypt(ctx, cbc, cbc); + os_memcpy(pos, cbc, AES_BLOCK_SIZE); + pos += AES_BLOCK_SIZE; + } + aes_encrypt_deinit(ctx); + return 0; +} + + +/** + * aes_128_cbc_decrypt - AES-128 CBC decryption + * @key: Decryption key + * @iv: Decryption IV for CBC mode (16 bytes) + * @data: Data to decrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int +aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; + u8 *pos = data; + int i, j, blocks; + + ctx = aes_decrypt_init(key, 16); + if (ctx == NULL) + return -1; + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + + blocks = data_len / AES_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, pos, AES_BLOCK_SIZE); + aes_decrypt(ctx, pos, pos); + for (j = 0; j < AES_BLOCK_SIZE; j++) + pos[j] ^= cbc[j]; + os_memcpy(cbc, tmp, AES_BLOCK_SIZE); + pos += AES_BLOCK_SIZE; + } + aes_decrypt_deinit(ctx); + return 0; +} diff --git a/components/wpa_supplicant/src/crypto/aes-internal-dec.c b/components/wpa_supplicant/src/crypto/aes-internal-dec.c new file mode 100644 index 0000000000..46371c5557 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/aes-internal-dec.c @@ -0,0 +1,172 @@ +/* + * AES (Rijndael) cipher - decrypt + * + * Modifications to public domain implementation: + * - support only 128-bit keys + * - cleanup + * - use C pre-processor to make it easier to change S table access + * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at + * cost of reduced throughput (quite small difference on Pentium 4, + * 10-25% when using -O1 or -O2 optimization) + * + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/aes_i.h" + + + +//static unsigned char aes_priv_buf[AES_PRIV_SIZE]; + +/** + * Expand the cipher key into the decryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +static int rijndaelKeySetupDec(u32 rk[], const u8 cipherKey[], int keyBits) +{ + int Nr, i, j; + u32 temp; + + /* expand the cipher key: */ + Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); + if (Nr < 0) + return Nr; + /* invert the order of the round keys: */ + for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the + * first and the last: */ + for (i = 1; i < Nr; i++) { + rk += 4; + for (j = 0; j < 4; j++) { + rk[j] = TD0_(TE4((rk[j] >> 24) )) ^ + TD1_(TE4((rk[j] >> 16) & 0xff)) ^ + TD2_(TE4((rk[j] >> 8) & 0xff)) ^ + TD3_(TE4((rk[j] ) & 0xff)); + } + } + + return Nr; +} + +void * aes_decrypt_init(const u8 *key, size_t len) +{ + u32 *rk; + int res; + rk = os_malloc(AES_PRIV_SIZE); + if (rk == NULL) + return NULL; + res = rijndaelKeySetupDec(rk, key, len * 8); + if (res < 0) { + os_free(rk); + return NULL; + } + rk[AES_PRIV_NR_POS] = res; + return rk; +} + +static void rijndaelDecrypt(const u32 rk[/*44*/], int Nr, const u8 ct[16], + u8 pt[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(ct ) ^ rk[0]; + s1 = GETU32(ct + 4) ^ rk[1]; + s2 = GETU32(ct + 8) ^ rk[2]; + s3 = GETU32(ct + 12) ^ rk[3]; + +#define ROUND(i,d,s) \ +d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \ +d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \ +d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \ +d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3] + +#ifdef FULL_UNROLL + + ROUND(1,t,s); + ROUND(2,s,t); + ROUND(3,t,s); + ROUND(4,s,t); + ROUND(5,t,s); + ROUND(6,s,t); + ROUND(7,t,s); + ROUND(8,s,t); + ROUND(9,t,s); + if (Nr > 10) { + ROUND(10,s,t); + ROUND(11,t,s); + if (Nr > 12) { + ROUND(12,s,t); + ROUND(13,t,s); + } + } + + rk += Nr << 2; + +#else /* !FULL_UNROLL */ + + /* Nr - 1 full rounds: */ + r = Nr >> 1; + for (;;) { + ROUND(1,t,s); + rk += 8; + if (--r == 0) + break; + ROUND(0,s,t); + } + +#endif /* ?FULL_UNROLL */ + +#undef ROUND + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0]; + PUTU32(pt , s0); + s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1]; + PUTU32(pt + 4, s1); + s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2]; + PUTU32(pt + 8, s2); + s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3]; + PUTU32(pt + 12, s3); +} + +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) +{ + u32 *rk = ctx; + rijndaelDecrypt(ctx, rk[AES_PRIV_NR_POS], crypt, plain); +} + + +void aes_decrypt_deinit(void *ctx) +{ + os_memset(ctx, 0, AES_PRIV_SIZE); + os_free(ctx); +} diff --git a/components/wpa_supplicant/src/crypto/aes-internal-enc.c b/components/wpa_supplicant/src/crypto/aes-internal-enc.c new file mode 100644 index 0000000000..7b1080c450 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/aes-internal-enc.c @@ -0,0 +1,134 @@ +/* + * AES (Rijndael) cipher - encrypt + * + * Modifications to public domain implementation: + * - support only 128-bit keys + * - cleanup + * - use C pre-processor to make it easier to change S table access + * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at + * cost of reduced throughput (quite small difference on Pentium 4, + * 10-25% when using -O1 or -O2 optimization) + * + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/aes_i.h" + +#include "os.h" + +void rijndaelEncrypt(const u32 rk[], int Nr, const u8 pt[16], u8 ct[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(pt ) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; + +#define ROUND(i,d,s) \ +d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ +d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ +d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ +d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] + +#ifdef FULL_UNROLL + + ROUND(1,t,s); + ROUND(2,s,t); + ROUND(3,t,s); + ROUND(4,s,t); + ROUND(5,t,s); + ROUND(6,s,t); + ROUND(7,t,s); + ROUND(8,s,t); + ROUND(9,t,s); + if (Nr > 10) { + ROUND(10,s,t); + ROUND(11,t,s); + if (Nr > 12) { + ROUND(12,s,t); + ROUND(13,t,s); + } + } + + rk += Nr << 2; + +#else /* !FULL_UNROLL */ + + /* Nr - 1 full rounds: */ + r = Nr >> 1; + for (;;) { + ROUND(1,t,s); + rk += 8; + if (--r == 0) + break; + ROUND(0,s,t); + } + +#endif /* ?FULL_UNROLL */ + +#undef ROUND + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; + PUTU32(ct , s0); + s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; + PUTU32(ct + 4, s1); + s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; + PUTU32(ct + 8, s2); + s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; + PUTU32(ct + 12, s3); +} + + +void * aes_encrypt_init(const u8 *key, size_t len) +{ + u32 *rk; + int res; + rk = os_malloc(AES_PRIV_SIZE); + if (rk == NULL) + return NULL; + res = rijndaelKeySetupEnc(rk, key, len * 8); + if (res < 0) { + os_free(rk); + return NULL; + } + rk[AES_PRIV_NR_POS] = res; + return rk; +} + + +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) +{ + u32 *rk = ctx; + rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt); +} + + +void aes_encrypt_deinit(void *ctx) +{ + os_memset(ctx, 0, AES_PRIV_SIZE); + os_free(ctx); +} diff --git a/components/wpa_supplicant/src/crypto/aes-internal.c b/components/wpa_supplicant/src/crypto/aes-internal.c new file mode 100644 index 0000000000..9618239f93 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/aes-internal.c @@ -0,0 +1,854 @@ +/* + * AES (Rijndael) cipher + * + * Modifications to public domain implementation: + * - support only 128-bit keys + * - cleanup + * - use C pre-processor to make it easier to change S table access + * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at + * cost of reduced throughput (quite small difference on Pentium 4, + * 10-25% when using -O1 or -O2 optimization) + * + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +//#include "wpa/common.h" +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/aes_i.h" + +/* + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define AES_SMALL_TABLES + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +const u32 Te0[256] /* ICACHE_RODATA_ATTR */ = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +#ifndef AES_SMALL_TABLES +const u32 Te1[256] /* ICACHE_RODATA_ATTR */ = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +const u32 Te2[256] /* ICACHE_RODATA_ATTR */ = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +const u32 Te3[256] /* ICACHE_RODATA_ATTR */ = { + + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; +const u32 Te4[256] /* ICACHE_RODATA_ATTR */ = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; +#endif /* AES_SMALL_TABLES */ +const u32 Td0[256] /* ICACHE_RODATA_ATTR */ = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +#ifndef AES_SMALL_TABLES +const u32 Td1[256] /* ICACHE_RODATA_ATTR */ = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +const u32 Td2[256] /* ICACHE_RODATA_ATTR */ = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +const u32 Td3[256] /* ICACHE_RODATA_ATTR */ = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +const u32 Td4[256] /* ICACHE_RODATA_ATTR */ = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; +const u32 rcon[] /* ICACHE_RODATA_ATTR */ = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; +#else /* AES_SMALL_TABLES */ +const u8 Td4s[256] /* ICACHE_RODATA_ATTR */ = { + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, + 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, + 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, + 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, + 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, + 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, + 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, + 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, + 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, + 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, + 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, + 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, + 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, + 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, + 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, + 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, + 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, + 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, + 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, + 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, + 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, + 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, + 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, + 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, + 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, + 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, + 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, + 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, + 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, + 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, +}; +const u8 rcons[] /* ICACHE_RODATA_ATTR */ = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; +#endif /* AES_SMALL_TABLES */ +/** + * Expand the cipher key into the encryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits) +{ + int i; + u32 temp; + + rk[0] = GETU32(cipherKey ); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + + if (keyBits == 128) { + for (i = 0; i < 10; i++) { + temp = rk[3]; + rk[4] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp) ^ RCON(i); + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + rk += 4; + } + return 10; + } + + rk[4] = GETU32(cipherKey + 16); + rk[5] = GETU32(cipherKey + 20); + + if (keyBits == 192) { + for (i = 0; i < 8; i++) { + temp = rk[5]; + rk[6] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp) ^ RCON(i); + rk[7] = rk[1] ^ rk[6]; + rk[8] = rk[2] ^ rk[7]; + rk[9] = rk[3] ^ rk[8]; + if (i == 7) + return 12; + rk[10] = rk[4] ^ rk[9]; + rk[11] = rk[5] ^ rk[10]; + rk += 6; + } + } + + rk[6] = GETU32(cipherKey + 24); + rk[7] = GETU32(cipherKey + 28); + + if (keyBits == 256) { + for (i = 0; i < 7; i++) { + temp = rk[7]; + rk[8] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp) ^ RCON(i); + rk[9] = rk[1] ^ rk[8]; + rk[10] = rk[2] ^ rk[9]; + rk[11] = rk[3] ^ rk[10]; + if (i == 6) + return 14; + temp = rk[11]; + rk[12] = rk[4] ^ TE411(temp) ^ TE422(temp) ^ + TE433(temp) ^ TE444(temp); + rk[13] = rk[5] ^ rk[12]; + rk[14] = rk[6] ^ rk[13]; + rk[15] = rk[7] ^ rk[14]; + rk += 8; + } + } + + return -1; +} diff --git a/components/wpa_supplicant/src/crypto/aes-unwrap.c b/components/wpa_supplicant/src/crypto/aes-unwrap.c new file mode 100644 index 0000000000..4a92f1cd31 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/aes-unwrap.c @@ -0,0 +1,80 @@ +/* + * AES key unwrap (128-bit KEK, RFC3394) + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/aes.h" +#include "crypto/aes_wrap.h" + +/** + * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * @kek: Key encryption key (KEK) + * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 + * bytes + * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits + * @plain: Plaintext key, n * 64 bits + * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) + */ +int +aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) +{ + u8 a[8], *r, b[16]; + int i, j; + void *ctx; + + /* 1) Initialize variables. */ + os_memcpy(a, cipher, 8); + r = plain; + os_memcpy(r, cipher + 8, 8 * n); + + ctx = aes_decrypt_init(kek, 16); + if (ctx == NULL) + return -1; + + /* 2) Compute intermediate values. + * For j = 5 to 0 + * For i = n to 1 + * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i + * A = MSB(64, B) + * R[i] = LSB(64, B) + */ + for (j = 5; j >= 0; j--) { + r = plain + (n - 1) * 8; + for (i = n; i >= 1; i--) { + os_memcpy(b, a, 8); + b[7] ^= n * j + i; + + os_memcpy(b + 8, r, 8); + aes_decrypt(ctx, b, b); + os_memcpy(a, b, 8); + os_memcpy(r, b + 8, 8); + r -= 8; + } + } + aes_decrypt_deinit(ctx); + + /* 3) Output results. + * + * These are already in @plain due to the location of temporary + * variables. Just verify that the IV matches with the expected value. + */ + for (i = 0; i < 8; i++) { + if (a[i] != 0xa6) + return -1; + } + + return 0; +} diff --git a/components/wpa_supplicant/src/crypto/aes-wrap.c b/components/wpa_supplicant/src/crypto/aes-wrap.c new file mode 100644 index 0000000000..388dd97a82 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/aes-wrap.c @@ -0,0 +1,70 @@ +/* + * AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/aes.h" +#include "crypto/aes_wrap.h" + +/** + * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * @kek: 16-octet Key encryption key (KEK) + * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 + * bytes + * @plain: Plaintext key to be wrapped, n * 64 bits + * @cipher: Wrapped key, (n + 1) * 64 bits + * Returns: 0 on success, -1 on failure + */ +int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) +{ + u8 *a, *r, b[16]; + int i, j; + void *ctx; + + a = cipher; + r = cipher + 8; + + /* 1) Initialize variables. */ + os_memset(a, 0xa6, 8); + os_memcpy(r, plain, 8 * n); + + ctx = aes_encrypt_init(kek, 16); + if (ctx == NULL) + return -1; + + /* 2) Calculate intermediate values. + * For j = 0 to 5 + * For i=1 to n + * B = AES(K, A | R[i]) + * A = MSB(64, B) ^ t where t = (n*j)+i + * R[i] = LSB(64, B) + */ + for (j = 0; j <= 5; j++) { + r = cipher + 8; + for (i = 1; i <= n; i++) { + os_memcpy(b, a, 8); + os_memcpy(b + 8, r, 8); + aes_encrypt(ctx, b, b); + os_memcpy(a, b, 8); + a[7] ^= n * j + i; + os_memcpy(r, b + 8, 8); + r += 8; + } + } + aes_encrypt_deinit(ctx); + + /* 3) Output the results. + * + * These are already in @cipher due to the location of temporary + * variables. + */ + + return 0; +} diff --git a/components/wpa_supplicant/src/crypto/bignum.c b/components/wpa_supplicant/src/crypto/bignum.c new file mode 100644 index 0000000000..7b8446c3ba --- /dev/null +++ b/components/wpa_supplicant/src/crypto/bignum.c @@ -0,0 +1,244 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" +#include "crypto/common.h" +#include "wpa/wpabuf.h" +#include "wpa/wpa_debug.h" +#include "bignum.h" + +#define CONFIG_INTERNAL_LIBTOMMATH +#ifdef CONFIG_INTERNAL_LIBTOMMATH +#include "libtommath.h" +#else /* CONFIG_INTERNAL_LIBTOMMATH */ +#include +#endif /* CONFIG_INTERNAL_LIBTOMMATH */ + + +/* + * The current version is just a wrapper for LibTomMath library, so + * struct bignum is just typecast to mp_int. + */ + +/** + * bignum_init - Allocate memory for bignum + * Returns: Pointer to allocated bignum or %NULL on failure + */ +struct bignum * +bignum_init(void) +{ + struct bignum *n = (struct bignum *)os_zalloc(sizeof(mp_int)); + if (n == NULL) + return NULL; + if (mp_init((mp_int *) n) != MP_OKAY) { + os_free(n); + n = NULL; + } + return n; +} + + +/** + * bignum_deinit - Free bignum + * @n: Bignum from bignum_init() + */ +void +bignum_deinit(struct bignum *n) +{ + if (n) { + mp_clear((mp_int *) n); + os_free(n); + } +} + + +/** + * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer + * @n: Bignum from bignum_init() + * Returns: Length of n if written to a binary buffer + */ +size_t +bignum_get_unsigned_bin_len(struct bignum *n) +{ + return mp_unsigned_bin_size((mp_int *) n); +} + + +/** + * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum + * @n: Bignum from bignum_init() + * @buf: Buffer for the binary number + * @len: Length of the buffer, can be %NULL if buffer is known to be long + * enough. Set to used buffer length on success if not %NULL. + * Returns: 0 on success, -1 on failure + */ +int +bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len) +{ + size_t need = mp_unsigned_bin_size((mp_int *) n); + if (len && need > *len) { + *len = need; + return -1; + } + if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + if (len) + *len = need; + return 0; +} + + +/** + * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer + * @n: Bignum from bignum_init(); to be set to the given value + * @buf: Buffer with unsigned binary value + * @len: Length of buf in octets + * Returns: 0 on success, -1 on failure + */ +int +bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len) +{ + if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_cmp - Signed comparison + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * Returns: 0 on success, -1 on failure + */ +int +bignum_cmp(const struct bignum *a, const struct bignum *b) +{ + return mp_cmp((mp_int *) a, (mp_int *) b); +} + + +/** + * bignum_cmd_d - Compare bignum to standard integer + * @a: Bignum from bignum_init() + * @b: Small integer + * Returns: 0 on success, -1 on failure + */ +int +bignum_cmp_d(const struct bignum *a, unsigned long b) +{ + return mp_cmp_d((mp_int *) a, b); +} + + +/** + * bignum_add - c = a + b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a + b + * Returns: 0 on success, -1 on failure + */ +int +bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_sub - c = a - b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a - b + * Returns: 0 on success, -1 on failure + */ +int +bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_mul - c = a * b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a * b + * Returns: 0 on success, -1 on failure + */ +int +bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_mulmod - d = a * b (mod c) + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); modulus + * @d: Bignum from bignum_init(); used to store the result of a * b (mod c) + * Returns: 0 on success, -1 on failure + */ +int +bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d) +{ + if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) + != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_exptmod - Modular exponentiation: d = a^b (mod c) + * @a: Bignum from bignum_init(); base + * @b: Bignum from bignum_init(); exponent + * @c: Bignum from bignum_init(); modulus + * @d: Bignum from bignum_init(); used to store the result of a^b (mod c) + * Returns: 0 on success, -1 on failure + */ +int +bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d) +{ + if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) + != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} diff --git a/components/wpa_supplicant/src/crypto/bignum.h b/components/wpa_supplicant/src/crypto/bignum.h new file mode 100644 index 0000000000..f25e26783a --- /dev/null +++ b/components/wpa_supplicant/src/crypto/bignum.h @@ -0,0 +1,38 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef BIGNUM_H +#define BIGNUM_H + +struct bignum; + +struct bignum * bignum_init(void); +void bignum_deinit(struct bignum *n); +size_t bignum_get_unsigned_bin_len(struct bignum *n); +int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len); +int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len); +int bignum_cmp(const struct bignum *a, const struct bignum *b); +int bignum_cmp_d(const struct bignum *a, unsigned long b); +int bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); +int bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); + +#endif /* BIGNUM_H */ diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c new file mode 100644 index 0000000000..7d89795797 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c @@ -0,0 +1,268 @@ +/* + * Crypto wrapper for internal crypto implementation - Cipher wrappers + * Copyright (c) 2006-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +//#include "wpa/includes.h" + +//#include "wpa/common.h" +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/aes.h" +#if defined(CONFIG_DES) || defined(CONFIG_DES3) +#include "crypto/des_i.h" +#endif + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + + +struct crypto_cipher { + enum crypto_cipher_alg alg; + union { + struct { + size_t used_bytes; + u8 key[16]; + size_t keylen; + } rc4; + struct { + u8 cbc[32]; + void *ctx_enc; + void *ctx_dec; + } aes; +#ifdef CONFIG_DES3 + struct { + struct des3_key_s key; + u8 cbc[8]; + } des3; +#endif +#ifdef CONFIG_DES + struct { + u32 ek[32]; + u32 dk[32]; + u8 cbc[8]; + } des; +#endif + } u; +}; + + +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len) +{ + struct crypto_cipher *ctx; + + ctx = (struct crypto_cipher *)os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->alg = alg; + + switch (alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (key_len > sizeof(ctx->u.rc4.key)) { + os_free(ctx); + return NULL; + } + ctx->u.rc4.keylen = key_len; + os_memcpy(ctx->u.rc4.key, key, key_len); + break; + case CRYPTO_CIPHER_ALG_AES: + ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len); + if (ctx->u.aes.ctx_enc == NULL) { + os_free(ctx); + return NULL; + } + ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len); + if (ctx->u.aes.ctx_dec == NULL) { + aes_encrypt_deinit(ctx->u.aes.ctx_enc); + os_free(ctx); + return NULL; + } + os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE); + break; +#ifdef CONFIG_DES3 + case CRYPTO_CIPHER_ALG_3DES: + if (key_len != 24) { + os_free(ctx); + return NULL; + } + des3_key_setup(key, &ctx->u.des3.key); + os_memcpy(ctx->u.des3.cbc, iv, 8); + break; +#endif +#ifdef CONFIG_DES + case CRYPTO_CIPHER_ALG_DES: + if (key_len != 8) { + os_free(ctx); + return NULL; + } + des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk); + os_memcpy(ctx->u.des.cbc, iv, 8); + break; +#endif + default: + os_free(ctx); + return NULL; + } + + return ctx; +} + + +int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, + u8 *crypt, size_t len) +{ + size_t i, j, blocks; + + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (plain != crypt) + os_memcpy(crypt, plain, len); + rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, + ctx->u.rc4.used_bytes, crypt, len); + ctx->u.rc4.used_bytes += len; + break; + case CRYPTO_CIPHER_ALG_AES: + if (len % AES_BLOCK_SIZE) + return -1; + blocks = len / AES_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + for (j = 0; j < AES_BLOCK_SIZE; j++) + ctx->u.aes.cbc[j] ^= plain[j]; + aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, + ctx->u.aes.cbc); + os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE); + plain += AES_BLOCK_SIZE; + crypt += AES_BLOCK_SIZE; + } + break; +#ifdef CONFIG_DES3 + case CRYPTO_CIPHER_ALG_3DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + for (j = 0; j < 8; j++) + ctx->u.des3.cbc[j] ^= plain[j]; + des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key, + ctx->u.des3.cbc); + os_memcpy(crypt, ctx->u.des3.cbc, 8); + plain += 8; + crypt += 8; + } + break; +#endif +#ifdef CONFIG_DES + case CRYPTO_CIPHER_ALG_DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + for (j = 0; j < 8; j++) + ctx->u.des3.cbc[j] ^= plain[j]; + des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek, + ctx->u.des.cbc); + os_memcpy(crypt, ctx->u.des.cbc, 8); + plain += 8; + crypt += 8; + } + break; +#endif + default: + return -1; + } + + return 0; +} + + +int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, + u8 *plain, size_t len) +{ + size_t i, j, blocks; + u8 tmp[32]; + + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (plain != crypt) + os_memcpy(plain, crypt, len); + rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, + ctx->u.rc4.used_bytes, plain, len); + ctx->u.rc4.used_bytes += len; + break; + case CRYPTO_CIPHER_ALG_AES: + if (len % AES_BLOCK_SIZE) + return -1; + blocks = len / AES_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, crypt, AES_BLOCK_SIZE); + aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); + for (j = 0; j < AES_BLOCK_SIZE; j++) + plain[j] ^= ctx->u.aes.cbc[j]; + os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE); + plain += AES_BLOCK_SIZE; + crypt += AES_BLOCK_SIZE; + } + break; +#ifdef CONFIG_DES3 + case CRYPTO_CIPHER_ALG_3DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, crypt, 8); + des3_decrypt(crypt, &ctx->u.des3.key, plain); + for (j = 0; j < 8; j++) + plain[j] ^= ctx->u.des3.cbc[j]; + os_memcpy(ctx->u.des3.cbc, tmp, 8); + plain += 8; + crypt += 8; + } + break; +#endif +#ifdef CONFIG_DES + case CRYPTO_CIPHER_ALG_DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, crypt, 8); + des_block_decrypt(crypt, ctx->u.des.dk, plain); + for (j = 0; j < 8; j++) + plain[j] ^= ctx->u.des.cbc[j]; + os_memcpy(ctx->u.des.cbc, tmp, 8); + plain += 8; + crypt += 8; + } + break; +#endif + default: + return -1; + } + + return 0; +} + + +void crypto_cipher_deinit(struct crypto_cipher *ctx) +{ + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_AES: + aes_encrypt_deinit(ctx->u.aes.ctx_enc); + aes_decrypt_deinit(ctx->u.aes.ctx_dec); + break; +#ifdef CONFIG_DES3 + case CRYPTO_CIPHER_ALG_3DES: + break; +#endif + default: + break; + } + os_free(ctx); +} diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c new file mode 100644 index 0000000000..ea97857005 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c @@ -0,0 +1,56 @@ +/* + * Crypto wrapper for internal crypto implementation - modexp + * Copyright (c) 2006-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "bignum.h" +#include "crypto/crypto.h" + + +int +crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len) +{ + struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; + int ret = -1; + + bn_base = bignum_init(); + bn_exp = bignum_init(); + bn_modulus = bignum_init(); + bn_result = bignum_init(); + + if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || + bn_result == NULL) + goto error; + + if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || + bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || + bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) + goto error; + + if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) + goto error; + + ret = bignum_get_unsigned_bin(bn_result, result, result_len); + +error: + bignum_deinit(bn_base); + bignum_deinit(bn_exp); + bignum_deinit(bn_modulus); + bignum_deinit(bn_result); + return ret; +} diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c new file mode 100644 index 0000000000..19934f063b --- /dev/null +++ b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c @@ -0,0 +1,111 @@ +/* + * Crypto wrapper for internal crypto implementation - RSA parts + * Copyright (c) 2006-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "crypto/common.h" +#include "crypto/crypto.h" + +#include "wpa/includes.h" +#include "wpa/common.h" +#include "wpa/wpa_debug.h" + +#include "wpa2/tls/rsa.h" +#include "wpa2/tls/pkcs1.h" +#include "wpa2/tls/pkcs8.h" + +/* Dummy structures; these are just typecast to struct crypto_rsa_key */ +struct crypto_public_key; +struct crypto_private_key; + + +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) +{ + return (struct crypto_public_key *) + crypto_rsa_import_public_key(key, len); +} + + +struct crypto_private_key * crypto_private_key_import(const u8 *key, + size_t len, + const char *passwd) +{ + struct crypto_private_key *res; + + /* First, check for possible PKCS #8 encoding */ + res = pkcs8_key_import(key, len); + if (res) + return res; + + if (passwd) { + /* Try to parse as encrypted PKCS #8 */ + res = pkcs8_enc_key_import(key, len, passwd); + if (res) + return res; + } + + /* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */ + wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private " + "key"); + return (struct crypto_private_key *) + crypto_rsa_import_private_key(key, len); +} + + +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, + size_t len) +{ + /* No X.509 support in crypto_internal.c */ + return NULL; +} + + +int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return pkcs1_encrypt(2, (struct crypto_rsa_key *) key, + 0, in, inlen, out, outlen); +} + + +int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key, + in, inlen, out, outlen); +} + + +int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return pkcs1_encrypt(1, (struct crypto_rsa_key *) key, + 1, in, inlen, out, outlen); +} + + +void crypto_public_key_free(struct crypto_public_key *key) +{ + crypto_rsa_free((struct crypto_rsa_key *) key); +} + + +void crypto_private_key_free(struct crypto_private_key *key) +{ + crypto_rsa_free((struct crypto_rsa_key *) key); +} + + +int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, + const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len) +{ + return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key, + crypt, crypt_len, plain, plain_len); +} diff --git a/components/wpa_supplicant/src/crypto/crypto_internal.c b/components/wpa_supplicant/src/crypto/crypto_internal.c new file mode 100644 index 0000000000..d8d59dfb9d --- /dev/null +++ b/components/wpa_supplicant/src/crypto/crypto_internal.c @@ -0,0 +1,280 @@ +/* + * Crypto wrapper for internal crypto implementation + * Copyright (c) 2006-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "crypto/includes.h" +#include "crypto/common.h" +//#include "wpa/common.h" +#include "crypto/crypto.h" +//#include "crypto/sha256_i.h" +#include "crypto/sha1_i.h" +#include "crypto/md5_i.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + + +struct crypto_hash { + enum crypto_hash_alg alg; + union { + struct MD5Context md5; + struct SHA1Context sha1; +#ifdef CONFIG_SHA256 + struct sha256_state sha256; +#endif /* CONFIG_SHA256 */ + } u; + u8 key[64]; + size_t key_len; +}; + + +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, + size_t key_len) +{ + struct crypto_hash *ctx; + u8 k_pad[64]; + u8 tk[32]; + size_t i; + + ctx = (struct crypto_hash *)os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->alg = alg; + + switch (alg) { + case CRYPTO_HASH_ALG_MD5: + MD5Init(&ctx->u.md5); + break; + case CRYPTO_HASH_ALG_SHA1: + SHA1Init(&ctx->u.sha1); + break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_SHA256: + sha256_init(&ctx->u.sha256); + break; +#endif /* CONFIG_SHA256 */ + case CRYPTO_HASH_ALG_HMAC_MD5: + if (key_len > sizeof(k_pad)) { + MD5Init(&ctx->u.md5); + MD5Update(&ctx->u.md5, key, key_len); + MD5Final(tk, &ctx->u.md5); + key = tk; + key_len = 16; + } + os_memcpy(ctx->key, key, key_len); + ctx->key_len = key_len; + + os_memcpy(k_pad, key, key_len); + if (key_len < sizeof(k_pad)) + os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x36; + MD5Init(&ctx->u.md5); + MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); + break; + case CRYPTO_HASH_ALG_HMAC_SHA1: + if (key_len > sizeof(k_pad)) { + SHA1Init(&ctx->u.sha1); + SHA1Update(&ctx->u.sha1, key, key_len); + SHA1Final(tk, &ctx->u.sha1); + key = tk; + key_len = 20; + } + os_memcpy(ctx->key, key, key_len); + ctx->key_len = key_len; + + os_memcpy(k_pad, key, key_len); + if (key_len < sizeof(k_pad)) + os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x36; + SHA1Init(&ctx->u.sha1); + SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); + break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_HMAC_SHA256: + if (key_len > sizeof(k_pad)) { + sha256_init(&ctx->u.sha256); + sha256_process(&ctx->u.sha256, key, key_len); + sha256_done(&ctx->u.sha256, tk); + key = tk; + key_len = 32; + } + os_memcpy(ctx->key, key, key_len); + ctx->key_len = key_len; + + os_memcpy(k_pad, key, key_len); + if (key_len < sizeof(k_pad)) + os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x36; + sha256_init(&ctx->u.sha256); + sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad)); + break; +#endif /* CONFIG_SHA256 */ + default: + os_free(ctx); + return NULL; + } + + return ctx; +} + + +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) +{ + if (ctx == NULL) + return; + + switch (ctx->alg) { + case CRYPTO_HASH_ALG_MD5: + case CRYPTO_HASH_ALG_HMAC_MD5: + MD5Update(&ctx->u.md5, data, len); + break; + case CRYPTO_HASH_ALG_SHA1: + case CRYPTO_HASH_ALG_HMAC_SHA1: + SHA1Update(&ctx->u.sha1, data, len); + break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_SHA256: + case CRYPTO_HASH_ALG_HMAC_SHA256: + sha256_process(&ctx->u.sha256, data, len); + break; +#endif /* CONFIG_SHA256 */ + default: + break; + } +} + + +int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) +{ + u8 k_pad[64]; + size_t i; + + if (ctx == NULL) + return -2; + + if (mac == NULL || len == NULL) { + os_free(ctx); + return 0; + } + + switch (ctx->alg) { + case CRYPTO_HASH_ALG_MD5: + if (*len < 16) { + *len = 16; + os_free(ctx); + return -1; + } + *len = 16; + MD5Final(mac, &ctx->u.md5); + break; + case CRYPTO_HASH_ALG_SHA1: + if (*len < 20) { + *len = 20; + os_free(ctx); + return -1; + } + *len = 20; + SHA1Final(mac, &ctx->u.sha1); + break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_SHA256: + if (*len < 32) { + *len = 32; + os_free(ctx); + return -1; + } + *len = 32; + sha256_done(&ctx->u.sha256, mac); + break; +#endif /* CONFIG_SHA256 */ + case CRYPTO_HASH_ALG_HMAC_MD5: + if (*len < 16) { + *len = 16; + os_free(ctx); + return -1; + } + *len = 16; + + MD5Final(mac, &ctx->u.md5); + + os_memcpy(k_pad, ctx->key, ctx->key_len); + os_memset(k_pad + ctx->key_len, 0, + sizeof(k_pad) - ctx->key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x5c; + MD5Init(&ctx->u.md5); + MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); + MD5Update(&ctx->u.md5, mac, 16); + MD5Final(mac, &ctx->u.md5); + break; + case CRYPTO_HASH_ALG_HMAC_SHA1: + if (*len < 20) { + *len = 20; + os_free(ctx); + return -1; + } + *len = 20; + + SHA1Final(mac, &ctx->u.sha1); + + os_memcpy(k_pad, ctx->key, ctx->key_len); + os_memset(k_pad + ctx->key_len, 0, + sizeof(k_pad) - ctx->key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x5c; + SHA1Init(&ctx->u.sha1); + SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); + SHA1Update(&ctx->u.sha1, mac, 20); + SHA1Final(mac, &ctx->u.sha1); + break; +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_HMAC_SHA256: + if (*len < 32) { + *len = 32; + os_free(ctx); + return -1; + } + *len = 32; + + sha256_done(&ctx->u.sha256, mac); + + os_memcpy(k_pad, ctx->key, ctx->key_len); + os_memset(k_pad + ctx->key_len, 0, + sizeof(k_pad) - ctx->key_len); + for (i = 0; i < sizeof(k_pad); i++) + k_pad[i] ^= 0x5c; + sha256_init(&ctx->u.sha256); + sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad)); + sha256_process(&ctx->u.sha256, mac, 32); + sha256_done(&ctx->u.sha256, mac); + break; +#endif /* CONFIG_SHA256 */ + default: + os_free(ctx); + return -1; + } + + os_free(ctx); + + return 0; +} + + +int crypto_global_init(void) +{ + return 0; +} + + +void crypto_global_deinit(void) +{ +} diff --git a/components/wpa_supplicant/src/crypto/dh_group5.c b/components/wpa_supplicant/src/crypto/dh_group5.c new file mode 100644 index 0000000000..710f5c7d02 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/dh_group5.c @@ -0,0 +1,43 @@ +/* + * Diffie-Hellman group 5 operations + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/dh_groups.h" +#include "crypto/dh_group5.h" + + +void * +dh5_init(struct wpabuf **priv, struct wpabuf **publ) +{ + *publ = dh_init(dh_groups_get(5), priv); + if (*publ == 0) + return NULL; + return (void *) 1; +} + + +struct wpabuf * +dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, + const struct wpabuf *own_private) +{ + return dh_derive_shared(peer_public, own_private, dh_groups_get(5)); +} + + +void +dh5_free(void *ctx) +{ +} diff --git a/components/wpa_supplicant/src/crypto/dh_groups.c b/components/wpa_supplicant/src/crypto/dh_groups.c new file mode 100644 index 0000000000..6ec9a36a90 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/dh_groups.c @@ -0,0 +1,641 @@ +/* + * Diffie-Hellman groups + * Copyright (c) 2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/random.h" +#include "crypto/dh_groups.h" +#include "wpa/wpabuf.h" +#include "wpa/wpa_debug.h" + +extern int crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len); + +#ifdef ALL_DH_GROUPS + +/* RFC 4306, B.1. Group 1 - 768 Bit MODP + * Generator: 2 + * Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } + */ +static const u8 dh_group1_generator[1] = { 0x02 }; +static const u8 dh_group1_prime[96] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 4306, B.2. Group 2 - 1024 Bit MODP + * Generator: 2 + * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } + */ +static const u8 dh_group2_generator[1] = { 0x02 }; +static const u8 dh_group2_prime[128] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +#endif /* ALL_DH_GROUPS */ + +/* RFC 3526, 2. Group 5 - 1536 Bit MODP + * Generator: 2 + * Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } + */ +static const u8 dh_group5_generator[1] = { 0x02 }; +static const u8 dh_group5_prime[192] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +#ifdef ALL_DH_GROUPS + +/* RFC 3526, 3. Group 14 - 2048 Bit MODP + * Generator: 2 + * Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } + */ +static const u8 dh_group14_generator[1] = { 0x02 }; +static const u8 dh_group14_prime[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 3526, 4. Group 15 - 3072 Bit MODP + * Generator: 2 + * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } + */ +static const u8 dh_group15_generator[1] = { 0x02 }; +static const u8 dh_group15_prime[384] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 3526, 5. Group 16 - 4096 Bit MODP + * Generator: 2 + * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } + */ +static const u8 dh_group16_generator[1] = { 0x02 }; +static const u8 dh_group16_prime[512] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, + 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, + 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, + 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, + 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, + 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, + 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, + 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, + 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, + 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, + 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, + 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 3526, 6. Group 17 - 6144 Bit MODP + * Generator: 2 + * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } + */ +static const u8 dh_group17_generator[1] = { 0x02 }; +static const u8 dh_group17_prime[768] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, + 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, + 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, + 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, + 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, + 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, + 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, + 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, + 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, + 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, + 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, + 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, + 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, + 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, + 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, + 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, + 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, + 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, + 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, + 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, + 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, + 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, + 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, + 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, + 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, + 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, + 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, + 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, + 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, + 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, + 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, + 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, + 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, + 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, + 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, + 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, + 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, + 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, + 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, + 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, + 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, + 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, + 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, + 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 3526, 7. Group 18 - 8192 Bit MODP + * Generator: 2 + * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } + */ +static const u8 dh_group18_generator[1] = { 0x02 }; +static const u8 dh_group18_prime[1024] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, + 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, + 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, + 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, + 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, + 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, + 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, + 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, + 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, + 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, + 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, + 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, + 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, + 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, + 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, + 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, + 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, + 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, + 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, + 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, + 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, + 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, + 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, + 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, + 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, + 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, + 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, + 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, + 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, + 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, + 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, + 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, + 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, + 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, + 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, + 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, + 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, + 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, + 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, + 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, + 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, + 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, + 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, + 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, + 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, + 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, + 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA, + 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, + 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, + 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, + 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, + 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, + 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, + 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, + 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, + 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, + 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, + 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, + 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8, + 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, + 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, + 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, + 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, + 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, + 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D, + 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, + 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, + 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, + 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, + 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, + 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B, + 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, + 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, + 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, + 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, + 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +#endif /* ALL_DH_GROUPS */ + + +#define DH_GROUP(id) \ +{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \ +dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) } + + +static struct dh_group dh_groups[] = { + DH_GROUP(5), +#ifdef ALL_DH_GROUPS + DH_GROUP(1), + DH_GROUP(2), + DH_GROUP(14), + DH_GROUP(15), + DH_GROUP(16), + DH_GROUP(17), + DH_GROUP(18) +#endif /* ALL_DH_GROUPS */ +}; + +#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0])) + + +const struct dh_group * +dh_groups_get(int id) +{ + size_t i; + + for (i = 0; i < NUM_DH_GROUPS; i++) { + if (dh_groups[i].id == id) + return &dh_groups[i]; + } + return NULL; +} + +/** + * dh_init - Initialize Diffie-Hellman handshake + * @dh: Selected Diffie-Hellman group + * @priv: Pointer for returning Diffie-Hellman private key + * Returns: Diffie-Hellman public value + */ +struct wpabuf * +dh_init(const struct dh_group *dh, struct wpabuf **priv) +{ + struct wpabuf *pv; + size_t pv_len; + + if (dh == NULL) + return NULL; + + wpabuf_free(*priv); + *priv = wpabuf_alloc(dh->prime_len); + if (*priv == NULL) + return NULL; + + if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) + { + wpabuf_free(*priv); + *priv = NULL; + return NULL; + } + + if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) { + /* Make sure private value is smaller than prime */ + *(wpabuf_mhead_u8(*priv)) = 0; + } + wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv); + + pv_len = dh->prime_len; + pv = wpabuf_alloc(pv_len); + if (pv == NULL) + return NULL; + if (crypto_mod_exp(dh->generator, dh->generator_len, + wpabuf_head(*priv), wpabuf_len(*priv), + dh->prime, dh->prime_len, wpabuf_mhead(pv), + &pv_len) < 0) { + wpabuf_free(pv); + wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); + return NULL; + } + wpabuf_put(pv, pv_len); + wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv); + + return pv; +} + + +/** + * dh_derive_shared - Derive shared Diffie-Hellman key + * @peer_public: Diffie-Hellman public value from peer + * @own_private: Diffie-Hellman private key from dh_init() + * @dh: Selected Diffie-Hellman group + * Returns: Diffie-Hellman shared key + */ +struct wpabuf * +dh_derive_shared(const struct wpabuf *peer_public, + const struct wpabuf *own_private, + const struct dh_group *dh) +{ + struct wpabuf *shared; + size_t shared_len; + + if (dh == NULL || peer_public == NULL || own_private == NULL) + return NULL; + + shared_len = dh->prime_len; + shared = wpabuf_alloc(shared_len); + if (shared == NULL) + return NULL; + if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), + wpabuf_head(own_private), wpabuf_len(own_private), + dh->prime, dh->prime_len, + wpabuf_mhead(shared), &shared_len) < 0) { + wpabuf_free(shared); + wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); + return NULL; + } + wpabuf_put(shared, shared_len); + wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared); + + return shared; +} diff --git a/components/wpa_supplicant/src/crypto/libtommath.h b/components/wpa_supplicant/src/crypto/libtommath.h new file mode 100644 index 0000000000..1010f9f63f --- /dev/null +++ b/components/wpa_supplicant/src/crypto/libtommath.h @@ -0,0 +1,3441 @@ +/* + * Minimal code for RSA support from LibTomMath 0.41 + * http://libtom.org/ + * http://libtom.org/files/ltm-0.41.tar.bz2 + * This library was released in public domain by Tom St Denis. + * + * The combination in this file may not use all of the optimized algorithms + * from LibTomMath and may be considerable slower than the LibTomMath with its + * default settings. The main purpose of having this version here is to make it + * easier to build bignum.c wrapper without having to install and build an + * external library. + * + * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this + * libtommath.c file instead of using the external LibTomMath library. + */ +//#include "c_types.h" +#include "os.h" +#include "stdarg.h" + + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#define BN_MP_INVMOD_C +#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would + * require BN_MP_EXPTMOD_FAST_C instead */ +#define BN_S_MP_MUL_DIGS_C +#define BN_MP_INVMOD_SLOW_C +#define BN_S_MP_SQR_C +#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this + * would require other than mp_reduce */ + +#ifdef LTM_FAST + +/* Use faster div at the cost of about 1 kB */ +#define BN_MP_MUL_D_C + +/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */ +#define BN_MP_EXPTMOD_FAST_C +#define BN_MP_MONTGOMERY_SETUP_C +#define BN_FAST_MP_MONTGOMERY_REDUCE_C +#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +#define BN_MP_MUL_2_C + +/* Include faster sqr at the cost of about 0.5 kB in code */ +#define BN_FAST_S_MP_SQR_C + +#else /* LTM_FAST */ + +#define BN_MP_DIV_SMALL +#define BN_MP_INIT_MULTI_C +#define BN_MP_CLEAR_MULTI_C +#define BN_MP_ABS_C +#endif /* LTM_FAST */ + +/* Current uses do not require support for negative exponent in exptmod, so we + * can save about 1.5 kB in leaving out invmod. */ +#define LTM_NO_NEG_EXP + +/* from tommath.h */ + +#ifndef MIN + #define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef MAX + #define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#define OPT_CAST(x) (x *) + +typedef unsigned long mp_digit; +typedef u64 mp_word; + +#define DIGIT_BIT 28 +#define MP_28BIT + + +#define XMALLOC os_malloc +#define XFREE os_free +#define XREALLOC os_realloc + + +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) + +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ + +#define MP_YES 1 /* yes response */ +#define MP_NO 0 /* no response */ + +typedef int mp_err; + +/* define this to use lower memory usage routines (exptmods mostly) */ +#define MP_LOW_MEM + +/* default precision */ +#ifndef MP_PREC + #ifndef MP_LOW_MEM + #define MP_PREC 32 /* default digits of precision */ + #else + #define MP_PREC 8 /* default digits of precision */ + #endif +#endif + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) +#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) + + +/* prototypes for copied functions */ +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); +static int s_mp_sqr(mp_int * a, mp_int * b); +static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs); + +static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); + +#ifdef BN_MP_INIT_MULTI_C +static int mp_init_multi(mp_int *mp, ...); +#endif +#ifdef BN_MP_CLEAR_MULTI_C +static void mp_clear_multi(mp_int *mp, ...); +#endif +static int mp_lshd(mp_int * a, int b); +static void mp_set(mp_int * a, mp_digit b); +static void mp_clamp(mp_int * a); +static void mp_exch(mp_int * a, mp_int * b); +static void mp_rshd(mp_int * a, int b); +static void mp_zero(mp_int * a); +static int mp_mod_2d(mp_int * a, int b, mp_int * c); +static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d); +static int mp_init_copy(mp_int * a, mp_int * b); +static int mp_mul_2d(mp_int * a, int b, mp_int * c); +#ifndef LTM_NO_NEG_EXP +static int mp_div_2(mp_int * a, mp_int * b); +static int mp_invmod(mp_int * a, mp_int * b, mp_int * c); +static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c); +#endif /* LTM_NO_NEG_EXP */ +static int mp_copy(mp_int * a, mp_int * b); +static int mp_count_bits(mp_int * a); +static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); +static int mp_mod(mp_int * a, mp_int * b, mp_int * c); +static int mp_grow(mp_int * a, int size); +static int mp_cmp_mag(mp_int * a, mp_int * b); +#ifdef BN_MP_ABS_C +static int mp_abs(mp_int * a, mp_int * b); +#endif +static int mp_sqr(mp_int * a, mp_int * b); +static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); +static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); +static int mp_2expt(mp_int * a, int b); +static int mp_reduce_setup(mp_int * a, mp_int * b); +static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu); +static int mp_init_size(mp_int * a, int size); +#ifdef BN_MP_EXPTMOD_FAST_C +static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +#endif /* BN_MP_EXPTMOD_FAST_C */ +#ifdef BN_FAST_S_MP_SQR_C +static int fast_s_mp_sqr (mp_int * a, mp_int * b); +#endif /* BN_FAST_S_MP_SQR_C */ +#ifdef BN_MP_MUL_D_C +static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); +#endif /* BN_MP_MUL_D_C */ + + + +/* functions from bn_.c */ + + +/* reverse an array, used for radix code */ +static void +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +static int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +static int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* init a new mp_int */ +static int +mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + + +/* clear one (frees) */ +static void +mp_clear (mp_int * a) +{ + int i; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + for (i = 0; i < a->used; i++) { + a->dp[i] = 0; + } + + /* free ram */ + XFREE(a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} + + +/* high level addition (handles signs) */ +static int +mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* high level subtraction (handles signs) */ +static int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + + +/* high level multiplication (handles sign) */ +static int +mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Toom-Cook? */ +#ifdef BN_MP_TOOM_MUL_C + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + } else +#endif +#ifdef BN_MP_KARATSUBA_MUL_C + /* use Karatsuba? */ + if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else +#endif + { + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ +#ifdef BN_FAST_S_MP_MUL_DIGS_C + int digs = a->used + b->used + 1; + + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else +#endif +#ifdef BN_S_MP_MUL_DIGS_C + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ +#else +#error mp_mul could fail + res = MP_VAL; +#endif + + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} + + +/* d = a * b (mod c) */ +static int +mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + + +/* c = a mod b, 0 <= c < b */ +static int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted a lot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +static int +mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { +#ifdef LTM_NO_NEG_EXP + return MP_VAL; +#else /* LTM_NO_NEG_EXP */ +#ifdef BN_MP_INVMOD_C + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; +#else +#error mp_exptmod would always fail + /* no invmod */ + return MP_VAL; +#endif +#endif /* LTM_NO_NEG_EXP */ + } + +/* modified diminished radix reduction */ +#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) + if (mp_reduce_is_2k_l(P) == MP_YES) { + return s_mp_exptmod(G, X, P, Y, 1); + } +#endif + +#ifdef BN_MP_DR_IS_MODULUS_C + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); +#else + /* default to no */ + dr = 0; +#endif + +#ifdef BN_MP_REDUCE_IS_2K_C + /* if not, is it a unrestricted DR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } +#endif + + /* if the modulus is odd or dr != 0 use the montgomery method */ +#ifdef BN_MP_EXPTMOD_FAST_C + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { +#endif +#ifdef BN_S_MP_EXPTMOD_C + (void) dr; + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod (G, X, P, Y, 0); +#else +#error mp_exptmod could fail + /* no exptmod for evens */ + return MP_VAL; +#endif +#ifdef BN_MP_EXPTMOD_FAST_C + } +#endif +} + + +/* compare two ints (signed)*/ +static int +mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + + +/* compare a digit */ +static int +mp_cmp_d(mp_int * a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + + +#ifndef LTM_NO_NEG_EXP +/* hac 14.61, pp608 */ +static int +mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + +#ifdef BN_FAST_MP_INVMOD_C + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } +#endif + +#ifdef BN_MP_INVMOD_SLOW_C + return mp_invmod_slow(a, b, c); +#endif + +#ifndef BN_FAST_MP_INVMOD_C +#ifndef BN_MP_INVMOD_SLOW_C +#error mp_invmod would always fail +#endif +#endif + return MP_VAL; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* get the size for an unsigned equivalent */ +static int +mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + + +#ifndef LTM_NO_NEG_EXP +/* hac 14.61, pp608 */ +static int +mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_mod(a, b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* compare maginitude of two ints (unsigned) */ +static int +mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} + + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +static int +mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + +#ifndef MP_8BIT + a->dp[0] |= *b++; + a->used += 1; +#else + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; +#endif + } + mp_clamp (a); + return MP_OKAY; +} + + +/* store in unsigned [big endian] format */ +static int +mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { +#ifndef MP_8BIT + b[x++] = (unsigned char) (t.dp[0] & 255); +#else + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); +#endif + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +static int +mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + + +static int +mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + + +/* set to zero */ +static void +mp_zero (mp_int * a) +{ + int n; + mp_digit *tmp; + + a->sign = MP_ZPOS; + a->used = 0; + + tmp = a->dp; + for (n = 0; n < a->alloc; n++) { + *tmp++ = 0; + } +} + + +/* copy, b = a */ +static int +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + + +/* shift right a certain amount of digits */ +static void +mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} + + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +static void +mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +static void +mp_clamp (mp_int * a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + + +/* grow as required */ +static int +mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + + +#ifdef BN_MP_ABS_C +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +static int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + + +/* set to a digit */ +static void +mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + + +#ifndef LTM_NO_NEG_EXP +/* b = a/2 */ +static int +mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* shift left by a certain bit count */ +static int +mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +#ifdef BN_MP_INIT_MULTI_C +static int +mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} +#endif + + +#ifdef BN_MP_CLEAR_MULTI_C +static void +mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} +#endif + + +/* shift left a certain amount of digits */ +static int +mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + + +/* returns the number of bits in an int */ +static int +mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + + +/* calc a value mod 2**b */ +static int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b >= (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + + +#ifdef BN_MP_DIV_SMALL + +/* slower bit-bang division... also smaller */ +static int +mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int ta, tb, tq, q; + int res, n, n2; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + /* init our temps */ + if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { + return res; + } + + + mp_set(&tq, 1); + n = mp_count_bits(a) - mp_count_bits(b); + if (((res = mp_abs(a, &ta)) != MP_OKAY) || + ((res = mp_abs(b, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { + goto LBL_ERR; + } + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || + ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { + goto LBL_ERR; + } + } + if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || + ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { + goto LBL_ERR; + } + } + + /* now q == quotient and ta == remainder */ + n = a->sign; + n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); + if (c != NULL) { + mp_exch(c, &q); + c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear_multi(&ta, &tb, &tq, &q, NULL); + return res; +} + +#else + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +static int +mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto LBL_Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto LBL_T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto LBL_X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto LBL_Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto LBL_Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto LBL_Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = x.used == 0 ? MP_ZPOS : a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +LBL_Y:mp_clear (&y); +LBL_X:mp_clear (&x); +LBL_T2:mp_clear (&t2); +LBL_T1:mp_clear (&t1); +LBL_Q:mp_clear (&q); + return res; +} + +#endif + + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +static int +s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_int*); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto LBL_M; + } + + if (redmode == 0) { + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce; + } else { + if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce_2k_l; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto LBL_MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + /* reduce modulo P */ + if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_MU; + } + if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_MU:mp_clear (&mu); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + + +/* computes b = a*a */ +static int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + +#ifdef BN_MP_TOOM_SQR_C + /* use Toom-Cook? */ + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + /* Karatsuba? */ + } else +#endif +#ifdef BN_MP_KARATSUBA_SQR_C +if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else +#endif + { +#ifdef BN_FAST_S_MP_SQR_C + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else +#endif +#ifdef BN_S_MP_SQR_C + res = s_mp_sqr (a, b); +#else +#error mp_sqr could fail + res = MP_VAL; +#endif + } + b->sign = MP_ZPOS; + return res; +} + + +/* reduces a modulo n where n is of the form 2**p - d + This differs from reduce_2k since "d" can be larger + than a single digit. +*/ +static int +mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + /* q = q * d */ + if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + + +/* determines the setup value */ +static int +mp_reduce_2k_setup_l(mp_int *a, mp_int *d) +{ + int res; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto ERR; + } + + if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear(&tmp); + return res; +} + + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +static int +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accommodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} + + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +static int +mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} + + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +static int +mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { +#ifdef BN_S_MP_MUL_HIGH_DIGS_C + if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#else + { +#error mp_reduce would always fail + res = MP_VAL; + goto CLEANUP; + } +#endif + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + if ((res = mp_add (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + + +/* multiplies |a| * |b| and only computes up to digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +static int +s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +static int +fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + register mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa+1; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +/* init an mp_init for a given size */ +static int +mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} + + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +static int +s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* default used is maximum possible size */ + t.used = 2*pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[2*ix]) + + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (2*ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = ((mp_word) *tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +static int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } +#endif + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + + +#ifdef BN_MP_MONTGOMERY_SETUP_C +/* setups the montgomery reduction stuff */ +static int +mp_montgomery_setup (mp_int * n, mp_digit * rho) +{ + mp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} +#endif + + +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int +fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + register mp_digit mu; + mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + register int iy; + register mp_digit *tmpn; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MUL_2_C +/* b = a*2 */ +static int +mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accommodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally up to just under + * the leading bit of b. This saves a lot of multiple precision shifting. + */ +static int +mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_EXPTMOD_FAST_C +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +static int +mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_SETUP_C + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto LBL_M; + } +#else + err = MP_VAL; + goto LBL_M; +#endif + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else +#endif + { +#ifdef BN_MP_MONTGOMERY_REDUCE_C + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + } else if (redmode == 1) { +#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } else { +#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto LBL_M; + } + redux = mp_reduce_2k; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_M; + } + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto LBL_RES; + } +#else + err = MP_VAL; + goto LBL_RES; +#endif + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* swap res with Y */ + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} +#endif + + +#ifdef BN_FAST_S_MP_SQR_C +/* the jist of squaring... + * you do like mult except the offset of the tmpx [one that + * starts closer to zero] can't equal the offset of tmpy. + * So basically you set up iy like before then you min it with + * (ty-tx) so that it never happens. You double all those + * you add in the inner loop + +After that loop you do the squares and add them in. +*/ + +static int +fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* get offsets into the two bignums */ + ty = MIN(a->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = a->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach at a rate of 2x + * and we have to round because odd cases need to be executed + */ + iy = MIN(iy, (ty-tx+1)>>1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); + } + + /* store it */ + W[ix] = (mp_digit)(_W & MP_MASK); + + /* make next carry */ + W1 = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MUL_D_C +/* multiply by a digit */ +static int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} +#endif diff --git a/components/wpa_supplicant/src/crypto/md5-internal.c b/components/wpa_supplicant/src/crypto/md5-internal.c new file mode 100644 index 0000000000..a430e297a5 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/md5-internal.c @@ -0,0 +1,298 @@ +/* + * MD5 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/md5.h" +#include "crypto/md5_i.h" +#include "crypto/crypto.h" + + +static void MD5Transform(u32 buf[4], u32 const in[16]); + + +typedef struct MD5Context MD5_CTX; + + +/** + * md5_vector - MD5 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + MD5_CTX ctx; + size_t i; + + MD5Init(&ctx); + for (i = 0; i < num_elem; i++) + MD5Update(&ctx, addr[i], len[i]); + MD5Final(mac, &ctx); + return 0; +} + + +/* ===== start - public domain MD5 implementation ===== */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#ifndef WORDS_BIGENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + u32 t; + do { + t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(u32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + os_memcpy(p, buf, len); + return; + } + os_memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + os_memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + os_memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + os_memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + os_memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + os_memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((u32 *) ctx->in)[14] = ctx->bits[0]; + ((u32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + os_memcpy(digest, ctx->buf, 16); + os_memset(ctx, 0, sizeof(struct MD5Context)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +MD5Transform(u32 buf[4], u32 const in[16]) +{ + register u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +/* ===== end - public domain MD5 implementation ===== */ diff --git a/components/wpa_supplicant/src/crypto/md5.c b/components/wpa_supplicant/src/crypto/md5.c new file mode 100644 index 0000000000..3125c98311 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/md5.c @@ -0,0 +1,113 @@ +/* + * MD5 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/md5.h" +#include "crypto/crypto.h" + + +/** + * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash (16 bytes) + * Returns: 0 on success, -1 on failure + */ +int +hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + u8 k_pad[64]; /* padding - key XORd with ipad/opad */ + u8 tk[16]; + const u8 *_addr[6]; + size_t i, _len[6]; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return -1; + } + + /* if key is longer than 64 bytes reset it to key = MD5(key) */ + if (key_len > 64) { + if (md5_vector(1, &key, &key_len, tk)) + return -1; + key = tk; + key_len = 16; + } + + /* the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner MD5 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + if (md5_vector(1 + num_elem, _addr, _len, mac)) + return -1; + + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer MD5 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = MD5_MAC_LEN; + return md5_vector(2, _addr, _len, mac); +} + + +/** + * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @data: Pointers to the data area + * @data_len: Length of the data area + * @mac: Buffer for the hash (16 bytes) + * Returns: 0 on success, -1 on failure + */ +int +hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); +} diff --git a/components/wpa_supplicant/src/crypto/rc4.c b/components/wpa_supplicant/src/crypto/rc4.c new file mode 100644 index 0000000000..678632297f --- /dev/null +++ b/components/wpa_supplicant/src/crypto/rc4.c @@ -0,0 +1,61 @@ +/* + * RC4 stream cipher + * Copyright (c) 2002-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/crypto.h" + +#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) + +int +rc4_skip(const u8 *key, size_t keylen, size_t skip, + u8 *data, size_t data_len) +{ + u32 i, j, k; + u8 S[256], *pos; + size_t kpos; + + /* Setup RC4 state */ + for (i = 0; i < 256; i++) + S[i] = i; + j = 0; + kpos = 0; + for (i = 0; i < 256; i++) { + j = (j + S[i] + key[kpos]) & 0xff; + kpos++; + if (kpos >= keylen) + kpos = 0; + S_SWAP(i, j); + } + + /* Skip the start of the stream */ + i = j = 0; + for (k = 0; k < skip; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + } + + /* Apply RC4 to data */ + pos = data; + for (k = 0; k < data_len; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + *pos++ ^= S[(S[i] + S[j]) & 0xff]; + } + + return 0; +} diff --git a/components/wpa_supplicant/src/crypto/sha1-internal.c b/components/wpa_supplicant/src/crypto/sha1-internal.c new file mode 100644 index 0000000000..a1c255e416 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha1-internal.c @@ -0,0 +1,313 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/sha1.h" +#include "crypto/sha1_i.h" +#include "crypto/md5.h" +#include "crypto/crypto.h" + +typedef struct SHA1Context SHA1_CTX; + +void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + + +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + SHA1_CTX ctx; + size_t i; + + SHA1Init(&ctx); + for (i = 0; i < num_elem; i++) + SHA1Update(&ctx, addr[i], len[i]); + SHA1Final(mac, &ctx); + return 0; +} + + +/* ===== start - public domain SHA1 implementation ===== */ + +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 4/01 +By Jouni Malinen +Minor changes to match the coding style used in Dynamics. + +Modified September 24, 2004 +By Jouni Malinen +Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. + +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#define SHA1HANDSOFF + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifndef WORDS_BIGENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ + (rol(block->l[i], 8) & 0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v,w,x,y,z,i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w=rol(w, 30); + + +#ifdef VERBOSE /* SAK */ +void SHAPrintContext(SHA1_CTX *context, char *msg) +{ + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); +} +#endif + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void +SHA1Transform(u32 state[5], const unsigned char buffer[64]) +{ + u32 a, b, c, d, e; + typedef union { + unsigned char c[64]; + u32 l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; +#ifdef SHA1HANDSOFF + CHAR64LONG16 workspace; + block = &workspace; + os_memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + os_memset(block, 0, 64); +#endif +} + + +/* SHA1Init - Initialize new context */ + +void +SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void +SHA1Update(SHA1_CTX* context, const void *_data, u32 len) +{ + u32 i, j; + const unsigned char *data = _data; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + os_memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + os_memcpy(&context->buffer[j], &data[i], len - i); +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ + +void +SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ + u32 i; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char) + ((context->count[(i >= 4 ? 0 : 1)] >> + ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *) "\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *) "\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() + */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & + 255); + } + /* Wipe variables */ + i = 0; + os_memset(context->buffer, 0, 64); + os_memset(context->state, 0, 20); + os_memset(context->count, 0, 8); + os_memset(finalcount, 0, 8); +} + +/* ===== end - public domain SHA1 implementation ===== */ diff --git a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c new file mode 100644 index 0000000000..915a23aa78 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -0,0 +1,101 @@ +/* + * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" +#include "crypto/common.h" +#include "crypto/sha1.h" +#include "crypto/md5.h" +#include "crypto/crypto.h" + +static int +pbkdf2_sha1_f(const char *passphrase, const char *ssid, + size_t ssid_len, int iterations, unsigned int count, + u8 *digest) +{ + unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; + int i, j; + unsigned char count_buf[4]; + const u8 *addr[2]; + size_t len[2]; + size_t passphrase_len = os_strlen(passphrase); + + addr[0] = (u8 *) ssid; + len[0] = ssid_len; + addr[1] = count_buf; + len[1] = 4; + + /* F(P, S, c, i) = U1 xor U2 xor ... Uc + * U1 = PRF(P, S || i) + * U2 = PRF(P, U1) + * Uc = PRF(P, Uc-1) + */ + + count_buf[0] = (count >> 24) & 0xff; + count_buf[1] = (count >> 16) & 0xff; + count_buf[2] = (count >> 8) & 0xff; + count_buf[3] = count & 0xff; + if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, + tmp)) + return -1; + os_memcpy(digest, tmp, SHA1_MAC_LEN); + + for (i = 1; i < iterations; i++) { + if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp, + SHA1_MAC_LEN, tmp2)) + return -1; + os_memcpy(tmp, tmp2, SHA1_MAC_LEN); + for (j = 0; j < SHA1_MAC_LEN; j++) + digest[j] ^= tmp2[j]; + } + + return 0; +} + + +/** + * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * @passphrase: ASCII passphrase + * @ssid: SSID + * @ssid_len: SSID length in bytes + * @iterations: Number of iterations to run + * @buf: Buffer for the generated key + * @buflen: Length of the buffer in bytes + * Returns: 0 on success, -1 of failure + * + * This function is used to derive PSK for WPA-PSK. For this protocol, + * iterations is set to 4096 and buflen to 32. This function is described in + * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. + */ +int +pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + unsigned int count = 0; + unsigned char *pos = buf; + size_t left = buflen, plen; + unsigned char digest[SHA1_MAC_LEN]; + + while (left > 0) { + count++; + if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, + count, digest)) + return -1; + plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; + os_memcpy(pos, digest, plen); + pos += plen; + left -= plen; + } + + return 0; +} diff --git a/components/wpa_supplicant/src/crypto/sha1.c b/components/wpa_supplicant/src/crypto/sha1.c new file mode 100644 index 0000000000..3d6da417ac --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha1.c @@ -0,0 +1,166 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/sha1.h" +#include "crypto/crypto.h" + + +/** + * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash (20 bytes) + * Returns: 0 on success, -1 on failure + */ +int +hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ + unsigned char tk[20]; + const u8 *_addr[6]; + size_t _len[6], i; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return -1; + } + + /* if key is longer than 64 bytes reset it to key = SHA1(key) */ + if (key_len > 64) { + if (sha1_vector(1, &key, &key_len, tk)) + return -1; + key = tk; + key_len = 20; + } + + /* the HMAC_SHA1 transform looks like: + * + * SHA1(K XOR opad, SHA1(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner SHA1 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + if (sha1_vector(1 + num_elem, _addr, _len, mac)) + return -1; + + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer SHA1 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = SHA1_MAC_LEN; + return sha1_vector(2, _addr, _len, mac); +} + + +/** + * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @data: Pointers to the data area + * @data_len: Length of the data area + * @mac: Buffer for the hash (20 bytes) + * Returns: 0 on success, -1 of failure + */ +int +hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); +} + +/** + * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) + * @key: Key for PRF + * @key_len: Length of the key in bytes + * @label: A unique label for each purpose of the PRF + * @data: Extra data to bind into the key + * @data_len: Length of the data + * @buf: Buffer for the generated pseudo-random key + * @buf_len: Number of bytes of key to generate + * Returns: 0 on success, -1 of failure + * + * This function is used to derive new, cryptographically separate keys from a + * given key (e.g., PMK in IEEE 802.11i). + */ +int +sha1_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len) +{ + u8 counter = 0; + size_t pos, plen; + u8 hash[SHA1_MAC_LEN]; + size_t label_len = os_strlen(label) + 1; + const unsigned char *addr[3]; + size_t len[3]; + + addr[0] = (u8 *) label; + len[0] = label_len; + addr[1] = data; + len[1] = data_len; + addr[2] = &counter; + len[2] = 1; + + pos = 0; + while (pos < buf_len) { + plen = buf_len - pos; + if (plen >= SHA1_MAC_LEN) { + if (hmac_sha1_vector(key, key_len, 3, addr, len, + &buf[pos])) + return -1; + pos += SHA1_MAC_LEN; + } else { + if (hmac_sha1_vector(key, key_len, 3, addr, len, + hash)) + return -1; + os_memcpy(&buf[pos], hash, plen); + break; + } + counter++; + } + + return 0; +} + diff --git a/components/wpa_supplicant/src/crypto/sha256-internal.c b/components/wpa_supplicant/src/crypto/sha256-internal.c new file mode 100644 index 0000000000..9a1fca1c17 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha256-internal.c @@ -0,0 +1,249 @@ +/* + * SHA-256 hash implementation and interface functions + * Copyright (c) 2003-2011, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/sha256.h" +#include "crypto/crypto.h" + +#define SHA256_BLOCK_SIZE 64 + +struct sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[SHA256_BLOCK_SIZE]; +}; + +static void sha256_init(struct sha256_state *md); +static int sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen); +static int sha256_done(struct sha256_state *md, unsigned char *out); + + +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + struct sha256_state ctx; + size_t i; + + sha256_init(&ctx); + for (i = 0; i < num_elem; i++) + if (sha256_process(&ctx, addr[i], len[i])) + return -1; + if (sha256_done(&ctx, mac)) + return -1; + return 0; +} + + +/* ===== start - public domain SHA256 implementation ===== */ + +/* This is based on SHA256 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. */ + +/* the K array */ +static const unsigned long K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + + +/* Various logical functions */ +#define RORc(x, y) \ +( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ + ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x), (n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +/* compress 512-bits */ +static int +sha256_compress(struct sha256_state *md, unsigned char *buf) +{ + u32 S[8], W[64], t0, t1; + u32 t; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + W[i] = WPA_GET_BE32(buf + (4 * i)); + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + + W[i - 16]; + } + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 64; ++i) { + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + return 0; +} + + +/* Initialize the hash state */ +static void +sha256_init(struct sha256_state *md) +{ + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ +static int +sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen) +{ + unsigned long n; + + if (md->curlen >= sizeof(md->buf)) + return -1; + + while (inlen > 0) { + if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) { + if (sha256_compress(md, (unsigned char *) in) < 0) + return -1; + md->length += SHA256_BLOCK_SIZE * 8; + in += SHA256_BLOCK_SIZE; + inlen -= SHA256_BLOCK_SIZE; + } else { + n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen)); + os_memcpy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == SHA256_BLOCK_SIZE) { + if (sha256_compress(md, md->buf) < 0) + return -1; + md->length += 8 * SHA256_BLOCK_SIZE; + md->curlen = 0; + } + } + } + + return 0; +} + + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful +*/ +static int +sha256_done(struct sha256_state *md, unsigned char *out) +{ + int i; + + if (md->curlen >= sizeof(md->buf)) + return -1; + + /* increase the length of the message */ + md->length += md->curlen * 8; + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char) 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 56) { + while (md->curlen < SHA256_BLOCK_SIZE) { + md->buf[md->curlen++] = (unsigned char) 0; + } + sha256_compress(md, md->buf); + md->curlen = 0; + } + + /* pad up to 56 bytes of zeroes */ + while (md->curlen < 56) { + md->buf[md->curlen++] = (unsigned char) 0; + } + + /* store length */ + WPA_PUT_BE64(md->buf + 56, md->length); + sha256_compress(md, md->buf); + + /* copy output */ + for (i = 0; i < 8; i++) + WPA_PUT_BE32(out + (4 * i), md->state[i]); + + return 0; +} + +/* ===== end - public domain SHA256 implementation ===== */ diff --git a/components/wpa_supplicant/src/crypto/sha256.c b/components/wpa_supplicant/src/crypto/sha256.c new file mode 100644 index 0000000000..f62cc11827 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/sha256.c @@ -0,0 +1,160 @@ +/* + * SHA-256 hash implementation and interface functions + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/sha256.h" +#include "crypto/crypto.h" + + +/** + * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash (32 bytes) + */ +void +hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ + unsigned char tk[32]; + const u8 *_addr[6]; + size_t _len[6], i; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return; + } + + /* if key is longer than 64 bytes reset it to key = SHA256(key) */ + if (key_len > 64) { + sha256_vector(1, &key, &key_len, tk); + key = tk; + key_len = 32; + } + + /* the HMAC_SHA256 transform looks like: + * + * SHA256(K XOR opad, SHA256(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner SHA256 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + sha256_vector(1 + num_elem, _addr, _len, mac); + + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer SHA256 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = SHA256_MAC_LEN; + sha256_vector(2, _addr, _len, mac); +} + + +/** + * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @data: Pointers to the data area + * @data_len: Length of the data area + * @mac: Buffer for the hash (20 bytes) + */ +void +hmac_sha256(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); +} + + +/** + * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) + * @key: Key for PRF + * @key_len: Length of the key in bytes + * @label: A unique label for each purpose of the PRF + * @data: Extra data to bind into the key + * @data_len: Length of the data + * @buf: Buffer for the generated pseudo-random key + * @buf_len: Number of bytes of key to generate + * + * This function is used to derive new, cryptographically separate keys from a + * given key. + */ +void +sha256_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len) +{ + u16 counter = 1; + size_t pos, plen; + u8 hash[SHA256_MAC_LEN]; + const u8 *addr[4]; + size_t len[4]; + u8 counter_le[2], length_le[2]; + + addr[0] = counter_le; + len[0] = 2; + addr[1] = (u8 *) label; + len[1] = os_strlen(label); + addr[2] = data; + len[2] = data_len; + addr[3] = length_le; + len[3] = sizeof(length_le); + + WPA_PUT_LE16(length_le, buf_len * 8); + pos = 0; + while (pos < buf_len) { + plen = buf_len - pos; + WPA_PUT_LE16(counter_le, counter); + if (plen >= SHA256_MAC_LEN) { + hmac_sha256_vector(key, key_len, 4, addr, len, + &buf[pos]); + pos += SHA256_MAC_LEN; + } else { + hmac_sha256_vector(key, key_len, 4, addr, len, hash); + os_memcpy(&buf[pos], hash, plen); + break; + } + counter++; + } +} diff --git a/components/xtensa-debug-module/component.mk b/components/xtensa-debug-module/component.mk new file mode 100755 index 0000000000..308f64f0ea --- /dev/null +++ b/components/xtensa-debug-module/component.mk @@ -0,0 +1,4 @@ +# +# Component Makefile +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/components/xtensa-debug-module/eri.c b/components/xtensa-debug-module/eri.c new file mode 100644 index 0000000000..fc96b531fe --- /dev/null +++ b/components/xtensa-debug-module/eri.c @@ -0,0 +1,32 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include "eri.h" + +uint32_t eri_read(int addr) { + uint32_t ret; + asm( + "RER %0,%1" + :"=r"(ret):"r"(addr) + ); + return ret; +} + +void eri_write(int addr, uint32_t data) { + asm volatile ( + "WER %0,%1" + ::"r"(data),"r"(addr) + ); +} + diff --git a/components/xtensa-debug-module/include/eri.h b/components/xtensa-debug-module/include/eri.h new file mode 100644 index 0000000000..33e4dd0918 --- /dev/null +++ b/components/xtensa-debug-module/include/eri.h @@ -0,0 +1,31 @@ +#ifndef ERI_H +#define ERI_H + +#include + +/* + The ERI is a bus internal to each Xtensa core. It connects, amongst others, to the debug interface, where it + allows reading/writing the same registers as available over JTAG. +*/ + + +/** + * @brief Perform an ERI read + * @param addr : ERI register to read from + * + * @return Value read + */ +uint32_t eri_read(int addr); + + +/** + * @brief Perform an ERI write + * @param addr : ERI register to write to + * @param data : Value to write + * + * @return Value read + */ +void eri_write(int addr, uint32_t data); + + +#endif \ No newline at end of file diff --git a/components/xtensa-debug-module/include/trax.h b/components/xtensa-debug-module/include/trax.h new file mode 100644 index 0000000000..c1b3608eb8 --- /dev/null +++ b/components/xtensa-debug-module/include/trax.h @@ -0,0 +1,62 @@ +#include "soc/dport_reg.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "eri.h" +#include "xtensa-debug-module.h" + + +typedef enum { + TRAX_DOWNCOUNT_WORDS, + TRAX_DOWNCOUNT_INSTRUCTIONS +} trax_downcount_unit_t; + +typedef enum { + TRAX_ENA_NONE = 0, + TRAX_ENA_PRO, + TRAX_ENA_APP, + TRAX_ENA_PRO_APP, + TRAX_ENA_PRO_APP_SWAP +} trax_ena_select_t; + + +/** + * @brief Enable the trax memory blocks to be used as Trax memory. + * + * @param pro_cpu_enable : true if Trax needs to be enabled for the pro CPU + * @param app_cpu_enable : true if Trax needs to be enabled for the pro CPU + * @param swap_regions : Normally, the pro CPU writes to Trax mem block 0 while + * the app cpu writes to block 1. Setting this to true + * inverts this. + * + * @return esp_err_t. Fails with ESP_ERR_NO_MEM if Trax enable is requested for 2 CPUs + * but memmap only has room for 1, or if Trax memmap is disabled + * entirely. + */ +int trax_enable(trax_ena_select_t ena); + +/** + * @brief Start a Trax trace on the current CPU + * + * @param units_until_stop : Set the units of the delay that gets passed to + * trax_trigger_traceend_after_delay. One of TRAX_DOWNCOUNT_WORDS + * or TRAX_DOWNCOUNT_INSTRUCTIONS. + * + * @return esp_err_t. Fails with ESP_ERR_NO_MEM if Trax is disabled. + */ +int trax_start_trace(trax_downcount_unit_t units_until_stop); + + +/** + * @brief Trigger a Trax trace stop after the indicated delay. If this is called + * before and the previous delay hasn't ended yet, this will overwrite + * that delay with the new value. The delay will always start at the time + * the function is called. + * + * @param delay : The delay to stop the trace in, in the unit indicated to + * trax_start_trace. Note: the trace memory has 4K words available. + * + * @return esp_err_t + */ +int trax_trigger_traceend_after_delay(int delay); + + diff --git a/components/xtensa-debug-module/include/xtensa-debug-module.h b/components/xtensa-debug-module/include/xtensa-debug-module.h new file mode 100644 index 0000000000..61b2182531 --- /dev/null +++ b/components/xtensa-debug-module/include/xtensa-debug-module.h @@ -0,0 +1,75 @@ +#ifndef XTENSA_DEBUG_MODULE_H +#define XTENSA_DEBUG_MODULE_H + +/* +ERI registers / OCD offsets and field definitions +*/ + +#define ERI_DEBUG_OFFSET 0x100000 + +#define ERI_TRAX_OFFSET (ERI_DEBUG_OFFSET+0) +#define ERI_PERFMON_OFFSET (ERI_DEBUG_OFFSET+0x1000) +#define ERI_OCDREG_OFFSET (ERI_DEBUG_OFFSET+0x2000) +#define ERI_MISCDBG_OFFSET (ERI_DEBUG_OFFSET+0x3000) +#define ERI_CORESIGHT_OFFSET (ERI_DEBUG_OFFSET+0x3F00) + +#define ERI_TRAX_TRAXID (ERI_TRAX_OFFSET+0x00) +#define ERI_TRAX_TRAXCTRL (ERI_TRAX_OFFSET+0x04) +#define ERI_TRAX_TRAXSTAT (ERI_TRAX_OFFSET+0x08) +#define ERI_TRAX_TRAXDATA (ERI_TRAX_OFFSET+0x0C) +#define ERI_TRAX_TRAXADDR (ERI_TRAX_OFFSET+0x10) +#define ERI_TRAX_TRIGGERPC (ERI_TRAX_OFFSET+0x14) +#define ERI_TRAX_PCMATCHCTRL (ERI_TRAX_OFFSET+0x18) +#define ERI_TRAX_DELAYCNT (ERI_TRAX_OFFSET+0x1C) +#define ERI_TRAX_MEMADDRSTART (ERI_TRAX_OFFSET+0x20) +#define ERI_TRAX_MEMADDREND (ERI_TRAX_OFFSET+0x24) + +#define TRAXCTRL_TREN (1<<0) //Trace enable. Tracing starts on 0->1 +#define TRAXCTRL_TRSTP (1<<1) //Trace Stop. Make 1 to stop trace. +#define TRAXCTRL_PCMEN (1<<2) //PC match enable +#define TRAXCTRL_PTIEN (1<<4) //Processor-trigger enable +#define TRAXCTRL_CTIEN (1<<5) //Cross-trigger enable +#define TRAXCTRL_TMEN (1<<7) //Tracemem Enable. Always set. +#define TRAXCTRL_CNTU (1<<9) //Post-stop-trigger countdown units; selects when DelayCount-- happens. + //0 - every 32-bit word written to tracemem, 1 - every cpu instruction +#define TRAXCTRL_TSEN (1<<11) //Undocumented/deprecated? +#define TRAXCTRL_SMPER_SHIFT 12 //Send sync every 2^(9-smper) messages. 7=reserved, 0=no sync msg +#define TRAXCTRL_SMPER_MASK 0x7 //Synchronization message period +#define TRAXCTRL_PTOWT (1<<16) //Processor Trigger Out (OCD halt) enabled when stop triggered +#define TRAXCTRL_PTOWS (1<<17) //Processor Trigger Out (OCD halt) enabled when trace stop completes +#define TRAXCTRL_CTOWT (1<<20) //Cross-trigger Out enabled when stop triggered +#define TRAXCTRL_CTOWS (1<<21) //Cross-trigger Out enabled when trace stop completes +#define TRAXCTRL_ITCTO (1<<22) //Integration mode: cross-trigger output +#define TRAXCTRL_ITCTIA (1<<23) //Integration mode: cross-trigger ack +#define TRAXCTRL_ITATV (1<<24) //replaces ATID when in integration mode: ATVALID output +#define TRAXCTRL_ATID_MASK 0x7F //ARB source ID +#define TRAXCTRL_ATID_SHIFT 24 +#define TRAXCTRL_ATEN (1<<31) //ATB interface enable + +#define TRAXSTAT_TRACT (1<<0) //Trace active flag. +#define TRAXSTAT_TRIG (1<<1) //Trace stop trigger. Clears on TREN 1->0 +#define TRAXSTAT_PCMTG (1<<2) //Stop trigger caused by PC match. Clears on TREN 1->0 +#define TRAXSTAT_PJTR (1<<3) //JTAG transaction result. 1=err in preceding jtag transaction. +#define TRAXSTAT_PTITG (1<<4) //Stop trigger caused by Processor Trigger Input. Clears on TREN 1->0 +#define TRAXSTAT_CTITG (1<<5) //Stop trigger caused by Cross-Trigger Input. Clears on TREN 1->0 +#define TRAXSTAT_MEMSZ_SHIFT 8 //Traceram size inducator. Usable trace ram is 2^MEMSZ bytes. +#define TRAXSTAT_MEMSZ_MASK 0x1F +#define TRAXSTAT_PTO (1<<16) //Processor Trigger Output: current value +#define TRAXSTAT_CTO (1<<17) //Cross-Trigger Output: current value +#define TRAXSTAT_ITCTOA (1<<22) //Cross-Trigger Out Ack: current value +#define TRAXSTAT_ITCTI (1<<23) //Cross-Trigger Input: current value +#define TRAXSTAT_ITATR (1<<24) //ATREADY Input: current value + +#define TRAXADDR_TADDR_SHIFT 0 //Trax memory address, in 32-bit words. +#define TRAXADDR_TADDR_MASK 0x1FFFFF //Actually is only as big as the trace buffer size max addr. +#define TRAXADDR_TWRAP_SHIFT 21 //Amount of times TADDR has overflown +#define TRAXADDR_TWRAP_MASK 0x3FF +#define TRAXADDR_TWSAT (1<<31) //1 if TWRAP has overflown, clear by disabling tren. + +#define PCMATCHCTRL_PCML_SHIFT 0 //Amount of lower bits to ignore in pc trigger register +#define PCMATCHCTRL_PCML_MASK 0x1F +#define PCMATCHCTRL_PCMS (1<<31) //PC Match Sense, 0 - match when procs PC is in-range, 1 - match when + //out-of-range + + +#endif \ No newline at end of file diff --git a/components/xtensa-debug-module/trax.c b/components/xtensa-debug-module/trax.c new file mode 100644 index 0000000000..5174e44776 --- /dev/null +++ b/components/xtensa-debug-module/trax.c @@ -0,0 +1,84 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include "soc/dport_reg.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "eri.h" +#include "xtensa-debug-module.h" +#include "trax.h" +#include "esp_log.h" + +#define TRACEMEM_MUX_PROBLK0_APPBLK1 0 +#define TRACEMEM_MUX_BLK0_ONLY 1 +#define TRACEMEM_MUX_BLK1_ONLY 2 +#define TRACEMEM_MUX_PROBLK1_APPBLK0 3 + +static const char* TAG = "trax"; + +int trax_enable(trax_ena_select_t which) +{ +#if !CONFIG_MEMMAP_TRACEMEM + ESP_LOGE(TAG, "Trax_enable called, but trax is disabled in menuconfig!"); + return ESP_ERR_NO_MEM; +#endif +#if !CONFIG_MEMMAP_TRACEMEM_TWOBANKS + if (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP) return ESP_ERR_NO_MEM; +#endif + if (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP) { + WRITE_PERI_REG(DPORT_TRACEMEM_MUX_MODE_REG, (which == TRAX_ENA_PRO_APP_SWAP)?TRACEMEM_MUX_PROBLK1_APPBLK0:TRACEMEM_MUX_PROBLK0_APPBLK1); + } else { + WRITE_PERI_REG(DPORT_TRACEMEM_MUX_MODE_REG, TRACEMEM_MUX_BLK0_ONLY); + } + WRITE_PERI_REG(DPORT_PRO_TRACEMEM_ENA_REG, (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP || which == TRAX_ENA_PRO)); + WRITE_PERI_REG(DPORT_APP_TRACEMEM_ENA_REG, (which == TRAX_ENA_PRO_APP || which == TRAX_ENA_PRO_APP_SWAP || which == TRAX_ENA_APP)); + return ESP_OK; +} + + +int trax_start_trace(trax_downcount_unit_t units_until_stop) +{ +#if !CONFIG_MEMMAP_TRACEMEM + ESP_LOGE(TAG, "Trax_start_trace called, but trax is disabled in menuconfig!"); + return ESP_ERR_NO_MEM; +#endif + uint32_t v; + if (eri_read(ERI_TRAX_TRAXSTAT)&TRAXSTAT_TRACT) { + ESP_LOGI(TAG, "Stopping active trace first."); + //Trace is active. Stop trace. + eri_write(ERI_TRAX_DELAYCNT, 0); + eri_write(ERI_TRAX_TRAXCTRL, eri_read(ERI_TRAX_TRAXCTRL)|TRAXCTRL_TRSTP); + //ToDo: This will probably trigger a trace done interrupt. ToDo: Fix, but how? -JD + eri_write(ERI_TRAX_TRAXCTRL, 0); + } + eri_write(ERI_TRAX_PCMATCHCTRL, 31); //do not stop at any pc match + v=TRAXCTRL_TREN | TRAXCTRL_TMEN | TRAXCTRL_PTOWS | (1</dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/ReadtheDocsTemplate" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ReadtheDocsTemplate" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/_static/doc-code-documentation-inline.png b/docs/_static/doc-code-documentation-inline.png new file mode 100644 index 0000000000..72bf22f156 Binary files /dev/null and b/docs/_static/doc-code-documentation-inline.png differ diff --git a/docs/_static/doc-code-documentation-rendered.png b/docs/_static/doc-code-documentation-rendered.png new file mode 100644 index 0000000000..d287d3c2e1 Binary files /dev/null and b/docs/_static/doc-code-documentation-rendered.png differ diff --git a/docs/_static/doc-code-function.png b/docs/_static/doc-code-function.png new file mode 100644 index 0000000000..758971ce72 Binary files /dev/null and b/docs/_static/doc-code-function.png differ diff --git a/docs/_static/doc-code-member.png b/docs/_static/doc-code-member.png new file mode 100644 index 0000000000..eee897a496 Binary files /dev/null and b/docs/_static/doc-code-member.png differ diff --git a/docs/_static/doc-code-void-function.png b/docs/_static/doc-code-void-function.png new file mode 100644 index 0000000000..36eeced6b8 Binary files /dev/null and b/docs/_static/doc-code-void-function.png differ diff --git a/docs/api/bt.rst b/docs/api/bt.rst new file mode 100644 index 0000000000..0ab17b2aa5 --- /dev/null +++ b/docs/api/bt.rst @@ -0,0 +1,38 @@ +Bluetooth +========= + +Overview +-------- + +`Instructions`_ + +Application Example +------------------- + +`Instructions`_ + +API Reference +------------- + +`Instructions`_ + +.. _Instructions: template.html + +Header Files +^^^^^^^^^^^^ + + * `bt/include/bt.h `_ + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygenstruct:: vhci_host_callback + +Functions +^^^^^^^^^ + +.. doxygenfunction:: API_vhci_host_check_send_available +.. doxygenfunction:: API_vhci_host_register_callback +.. doxygenfunction:: API_vhci_host_send_packet +.. doxygenfunction:: bt_controller_init + diff --git a/docs/api/esp_wifi.rst b/docs/api/esp_wifi.rst new file mode 100644 index 0000000000..c13d3d751a --- /dev/null +++ b/docs/api/esp_wifi.rst @@ -0,0 +1,80 @@ +Wi-Fi +===== + +Overview +-------- + +`Instructions`_ + +Application Example +------------------- + +`Instructions`_ + +API Reference +------------- + +`Instructions`_ + +.. _Instructions: template.html + +Header Files +^^^^^^^^^^^^ + + * `esp32/include/esp_wifi.h `_ + +Macros +------ + +.. doxygendefine:: WIFI_INIT_CONFIG_DEFAULT + + +Type Definitions +---------------- + +.. doxygentypedef:: wifi_promiscuous_cb_t +.. doxygentypedef:: esp_vendor_ie_cb_t + +Functions +--------- + +.. doxygenfunction:: esp_wifi_init +.. doxygenfunction:: esp_wifi_deinit +.. doxygenfunction:: esp_wifi_set_mode +.. doxygenfunction:: esp_wifi_get_mode +.. doxygenfunction:: esp_wifi_start +.. doxygenfunction:: esp_wifi_stop +.. doxygenfunction:: esp_wifi_connect +.. doxygenfunction:: esp_wifi_disconnect +.. doxygenfunction:: esp_wifi_clear_fast_connect +.. doxygenfunction:: esp_wifi_deauth_sta +.. doxygenfunction:: esp_wifi_scan_start +.. doxygenfunction:: esp_wifi_scan_stop +.. doxygenfunction:: esp_wifi_scan_get_ap_num +.. doxygenfunction:: esp_wifi_scan_get_ap_records +.. doxygenfunction:: esp_wifi_sta_get_ap_info +.. doxygenfunction:: esp_wifi_set_ps +.. doxygenfunction:: esp_wifi_get_ps +.. doxygenfunction:: esp_wifi_set_protocol +.. doxygenfunction:: esp_wifi_get_protocol +.. doxygenfunction:: esp_wifi_set_bandwidth +.. doxygenfunction:: esp_wifi_get_bandwidth +.. doxygenfunction:: esp_wifi_set_channel +.. doxygenfunction:: esp_wifi_get_channel +.. doxygenfunction:: esp_wifi_set_country +.. doxygenfunction:: esp_wifi_get_country +.. doxygenfunction:: esp_wifi_set_mac +.. doxygenfunction:: esp_wifi_get_mac +.. doxygenfunction:: esp_wifi_set_promiscuous_rx_cb +.. doxygenfunction:: esp_wifi_set_promiscuous +.. doxygenfunction:: esp_wifi_get_promiscuous +.. doxygenfunction:: esp_wifi_set_config +.. doxygenfunction:: esp_wifi_get_config +.. doxygenfunction:: esp_wifi_ap_get_sta_list +.. doxygenfunction:: esp_wifi_set_storage +.. doxygenfunction:: esp_wifi_set_auto_connect +.. doxygenfunction:: esp_wifi_get_auto_connect +.. doxygenfunction:: esp_wifi_set_vendor_ie +.. doxygenfunction:: esp_wifi_set_vendor_ie_cb + + diff --git a/docs/api/gpio.rst b/docs/api/gpio.rst new file mode 100644 index 0000000000..0cd4eca365 --- /dev/null +++ b/docs/api/gpio.rst @@ -0,0 +1,138 @@ +GPIO +==== + +Overview +-------- + +`Instructions`_ + +Application Example +------------------- + +`Instructions`_ + +API Reference +------------- + +`Instructions`_ + +.. _Instructions: template.html + +Header Files +^^^^^^^^^^^^ + + * `driver/include/driver/driver/gpio.h `_ + +Macros +^^^^^^ + +.. doxygendefine:: GPIO_SEL_0 +.. doxygendefine:: GPIO_SEL_1 +.. doxygendefine:: GPIO_SEL_2 +.. doxygendefine:: GPIO_SEL_3 +.. doxygendefine:: GPIO_SEL_4 +.. doxygendefine:: GPIO_SEL_5 +.. doxygendefine:: GPIO_SEL_6 +.. doxygendefine:: GPIO_SEL_7 +.. doxygendefine:: GPIO_SEL_8 +.. doxygendefine:: GPIO_SEL_9 +.. doxygendefine:: GPIO_SEL_10 +.. doxygendefine:: GPIO_SEL_11 +.. doxygendefine:: GPIO_SEL_12 +.. doxygendefine:: GPIO_SEL_13 +.. doxygendefine:: GPIO_SEL_14 +.. doxygendefine:: GPIO_SEL_15 +.. doxygendefine:: GPIO_SEL_16 +.. doxygendefine:: GPIO_SEL_17 +.. doxygendefine:: GPIO_SEL_18 +.. doxygendefine:: GPIO_SEL_19 +.. doxygendefine:: GPIO_SEL_21 +.. doxygendefine:: GPIO_SEL_22 +.. doxygendefine:: GPIO_SEL_23 +.. doxygendefine:: GPIO_SEL_25 +.. doxygendefine:: GPIO_SEL_26 +.. doxygendefine:: GPIO_SEL_27 +.. doxygendefine:: GPIO_SEL_32 +.. doxygendefine:: GPIO_SEL_33 +.. doxygendefine:: GPIO_SEL_34 +.. doxygendefine:: GPIO_SEL_35 +.. doxygendefine:: GPIO_SEL_36 +.. doxygendefine:: GPIO_SEL_37 +.. doxygendefine:: GPIO_SEL_38 +.. doxygendefine:: GPIO_SEL_39 +.. doxygendefine:: GPIO_PIN_REG_0 +.. doxygendefine:: GPIO_PIN_REG_1 +.. doxygendefine:: GPIO_PIN_REG_2 +.. doxygendefine:: GPIO_PIN_REG_3 +.. doxygendefine:: GPIO_PIN_REG_4 +.. doxygendefine:: GPIO_PIN_REG_5 +.. doxygendefine:: GPIO_PIN_REG_6 +.. doxygendefine:: GPIO_PIN_REG_7 +.. doxygendefine:: GPIO_PIN_REG_8 +.. doxygendefine:: GPIO_PIN_REG_9 +.. doxygendefine:: GPIO_PIN_REG_10 +.. doxygendefine:: GPIO_PIN_REG_11 +.. doxygendefine:: GPIO_PIN_REG_12 +.. doxygendefine:: GPIO_PIN_REG_13 +.. doxygendefine:: GPIO_PIN_REG_14 +.. doxygendefine:: GPIO_PIN_REG_15 +.. doxygendefine:: GPIO_PIN_REG_16 +.. doxygendefine:: GPIO_PIN_REG_17 +.. doxygendefine:: GPIO_PIN_REG_18 +.. doxygendefine:: GPIO_PIN_REG_19 +.. doxygendefine:: GPIO_PIN_REG_20 +.. doxygendefine:: GPIO_PIN_REG_21 +.. doxygendefine:: GPIO_PIN_REG_22 +.. doxygendefine:: GPIO_PIN_REG_23 +.. doxygendefine:: GPIO_PIN_REG_25 +.. doxygendefine:: GPIO_PIN_REG_26 +.. doxygendefine:: GPIO_PIN_REG_27 +.. doxygendefine:: GPIO_PIN_REG_32 +.. doxygendefine:: GPIO_PIN_REG_33 +.. doxygendefine:: GPIO_PIN_REG_34 +.. doxygendefine:: GPIO_PIN_REG_35 +.. doxygendefine:: GPIO_PIN_REG_36 +.. doxygendefine:: GPIO_PIN_REG_37 +.. doxygendefine:: GPIO_PIN_REG_38 +.. doxygendefine:: GPIO_PIN_REG_39 +.. doxygendefine:: GPIO_APP_CPU_INTR_ENA +.. doxygendefine:: GPIO_APP_CPU_NMI_INTR_ENA +.. doxygendefine:: GPIO_PRO_CPU_INTR_ENA +.. doxygendefine:: GPIO_PRO_CPU_NMI_INTR_ENA +.. doxygendefine:: GPIO_SDIO_EXT_INTR_ENA +.. doxygendefine:: GPIO_MODE_DEF_INPUT +.. doxygendefine:: GPIO_MODE_DEF_OUTPUT +.. doxygendefine:: GPIO_MODE_DEF_OD +.. doxygendefine:: GPIO_PIN_COUNT +.. doxygendefine:: GPIO_IS_VALID_GPIO +.. doxygendefine:: GPIO_IS_VALID_OUTPUT_GPIO + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygentypedef:: gpio_event_callback + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: gpio_num_t +.. doxygenenum:: gpio_int_type_t +.. doxygenenum:: gpio_mode_t +.. doxygenenum:: gpio_pullup_t +.. doxygenenum:: gpio_pulldown_t +.. doxygenenum:: gpio_pull_mode_t + +Functions +^^^^^^^^^ + +.. doxygenfunction:: gpio_config +.. doxygenfunction:: gpio_set_intr_type +.. doxygenfunction:: gpio_intr_enable +.. doxygenfunction:: gpio_intr_disable +.. doxygenfunction:: gpio_set_level +.. doxygenfunction:: gpio_get_level +.. doxygenfunction:: gpio_set_direction +.. doxygenfunction:: gpio_set_pull_mode +.. doxygenfunction:: gpio_wakeup_enable +.. doxygenfunction:: gpio_wakeup_disable +.. doxygenfunction:: gpio_isr_register diff --git a/docs/api/ledc.rst b/docs/api/ledc.rst new file mode 100644 index 0000000000..f379e9d008 --- /dev/null +++ b/docs/api/ledc.rst @@ -0,0 +1,66 @@ +LED Control +=========== + +Overview +-------- + +`Instructions`_ + +Application Example +------------------- + +`Instructions`_ + +API Reference +------------- + +`Instructions`_ + +.. _Instructions: template.html + +Header Files +^^^^^^^^^^^^ + + * `driver/include/driver/ledc.h `_ + +Data Structures +^^^^^^^^^^^^^^^ + +.. doxygenstruct:: ledc_channel_config_t +.. doxygenstruct:: ledc_timer_config_t + +Macros +^^^^^^ + +.. doxygendefine:: LEDC_APB_CLK_HZ +.. doxygendefine:: LEDC_REF_CLK_HZ + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: ledc_mode_t +.. doxygenenum:: ledc_intr_type_t +.. doxygenenum:: ledc_duty_direction_t +.. doxygenenum:: ledc_clk_src_t +.. doxygenenum:: ledc_timer_t +.. doxygenenum:: ledc_channel_t +.. doxygenenum:: ledc_timer_bit_t + +Functions +^^^^^^^^^ + +.. doxygenfunction:: ledc_channel_config +.. doxygenfunction:: ledc_timer_config +.. doxygenfunction:: ledc_update_duty +.. doxygenfunction:: ledc_stop +.. doxygenfunction:: ledc_set_freq +.. doxygenfunction:: ledc_get_freq +.. doxygenfunction:: ledc_set_duty +.. doxygenfunction:: ledc_get_duty +.. doxygenfunction:: ledc_set_fade +.. doxygenfunction:: ledc_isr_register +.. doxygenfunction:: ledc_timer_set +.. doxygenfunction:: ledc_timer_rst +.. doxygenfunction:: ledc_timer_pause +.. doxygenfunction:: ledc_timer_resume +.. doxygenfunction:: ledc_bind_channel_timer diff --git a/docs/api/log.rst b/docs/api/log.rst new file mode 100644 index 0000000000..d2f2fcd073 --- /dev/null +++ b/docs/api/log.rst @@ -0,0 +1,68 @@ +.. include:: ../../components/log/README.rst + +Application Example +------------------- + +`Instructions`_ + +API Reference +------------- + +`Instructions`_ + +.. _Instructions: template.html + +Header Files +^^^^^^^^^^^^ + + * `log/include/esp_log.h `_ + +Macros +^^^^^^ + +.. doxygendefine:: LOG_COLOR_E +.. doxygendefine:: LOG_COLOR_W +.. doxygendefine:: LOG_COLOR_I +.. doxygendefine:: LOG_COLOR_D +.. doxygendefine:: LOG_COLOR_V +.. doxygendefine:: LOG_RESET_COLOR +.. doxygendefine:: LOG_FORMAT +.. doxygendefine:: LOG_LOCAL_LEVEL +.. doxygendefine:: ESP_EARLY_LOGE +.. doxygendefine:: ESP_EARLY_LOGW +.. doxygendefine:: ESP_EARLY_LOGI +.. doxygendefine:: ESP_EARLY_LOGD +.. doxygendefine:: ESP_EARLY_LOGV +.. doxygendefine:: ESP_LOGE +.. doxygendefine:: ESP_LOGW +.. doxygendefine:: ESP_LOGI +.. doxygendefine:: ESP_LOGD +.. doxygendefine:: ESP_LOGV + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygentypedef:: vprintf_like_t + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: esp_log_level_t + +Functions +^^^^^^^^^ + +.. doxygenfunction:: esp_log_level_set +.. doxygenfunction:: esp_log_set_vprintf +.. doxygenfunction:: esp_log_timestamp +.. doxygenfunction:: esp_log_write + + + + + + + + + + diff --git a/docs/api/nvs_flash.rst b/docs/api/nvs_flash.rst new file mode 100644 index 0000000000..0768fa5597 --- /dev/null +++ b/docs/api/nvs_flash.rst @@ -0,0 +1,73 @@ +.. include:: ../../components/nvs_flash/README.rst + +Application Example +------------------- + +`Instructions `_ + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * `nvs_flash/include/nvs_flash.h `_ + * `nvs_flash/include/nvs.h `_ + +Macros +^^^^^^ + +.. doxygendefine:: ESP_ERR_NVS_BASE +.. doxygendefine:: ESP_ERR_NVS_NOT_INITIALIZED +.. doxygendefine:: ESP_ERR_NVS_NOT_FOUND +.. doxygendefine:: ESP_ERR_NVS_TYPE_MISMATCH +.. doxygendefine:: ESP_ERR_NVS_READ_ONLY +.. doxygendefine:: ESP_ERR_NVS_NOT_ENOUGH_SPACE +.. doxygendefine:: ESP_ERR_NVS_INVALID_NAME +.. doxygendefine:: ESP_ERR_NVS_INVALID_HANDLE +.. doxygendefine:: ESP_ERR_NVS_REMOVE_FAILED +.. doxygendefine:: ESP_ERR_NVS_KEY_TOO_LONG +.. doxygendefine:: ESP_ERR_NVS_PAGE_FULL +.. doxygendefine:: ESP_ERR_NVS_INVALID_STATE +.. doxygendefine:: ESP_ERR_NVS_INVALID_LENGTH + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygentypedef:: nvs_handle + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: nvs_open_mode + +Functions +^^^^^^^^^ +.. doxygenfunction:: nvs_open +.. doxygenfunction:: nvs_set_i8 +.. doxygenfunction:: nvs_set_u8 +.. doxygenfunction:: nvs_set_i16 +.. doxygenfunction:: nvs_set_u16 +.. doxygenfunction:: nvs_set_i32 +.. doxygenfunction:: nvs_set_u32 +.. doxygenfunction:: nvs_set_i64 +.. doxygenfunction:: nvs_set_u64 +.. doxygenfunction:: nvs_set_str +.. doxygenfunction:: nvs_set_blob +.. doxygenfunction:: nvs_get_i8 +.. doxygenfunction:: nvs_get_u8 +.. doxygenfunction:: nvs_get_i16 +.. doxygenfunction:: nvs_get_u16 +.. doxygenfunction:: nvs_get_i32 +.. doxygenfunction:: nvs_get_u32 +.. doxygenfunction:: nvs_get_i64 +.. doxygenfunction:: nvs_get_u64 +.. doxygenfunction:: nvs_get_str +.. doxygenfunction:: nvs_get_blob +.. doxygenfunction:: nvs_erase_key +.. doxygenfunction:: nvs_erase_all +.. doxygenfunction:: nvs_commit +.. doxygenfunction:: nvs_close +.. doxygenfunction:: nvs_flash_init +.. doxygenfunction:: nvs_flash_init_custom + diff --git a/docs/api/template.rst b/docs/api/template.rst new file mode 100644 index 0000000000..6feb7ba271 --- /dev/null +++ b/docs/api/template.rst @@ -0,0 +1,110 @@ +Template +======== + +.. note:: + + *INSTRUCTIONS* + + 1. Use this file as a template to document API. + 2. Change the file name to the name of the header file that represents documented API. + 3. Include respective files with descriptions from the API folder using ``..include::`` + + * README.rst + * example.rst + + 4. Optionally provide description right in this file. + 5. Once done, remove all instructions like this one and any superfluous headers. + +Overview +-------- + +.. note:: + + *INSTRUCTIONS* + + 1. Provide overview where and how this API may be used. + 2. Where applicable include code snippets to illustrate functionality of particular functions. + 3. To distinguish between sections, use the following `heading levels `_: + + * ``#`` with overline, for parts + * ``*`` with overline, for chapters + * ``=``, for sections + * ``-``, for subsections + * ``^``, for subsubsections + * ``"``, for paragraphs + +Application Example +------------------- + +.. note:: + + *INSTRUCTIONS* + + 1. Provide one or more practical examples to demonstrate functionality of this API. + 2. Break down the code into parts and describe functionality of each part. + 3. Provide screenshots if applicable. + +API Reference +------------- + +.. note:: + + *INSTRUCTIONS* + + 1. Specify the names of header files used to generate this reference. Each name should be linked to the source on `espressif/esp-idf `_ repository. + 2. Provide list of API members divided into sections. + 3. Use corresponding ``.. doxygen..`` directives, so member documentation is auto updated. + + * Data Structures -``.. doxygenstruct::`` together with ``:members:`` + * Macros - ``.. doxygendefine::`` + * Type Definitions - ``.. doxygentypedef::`` + * Enumerations - ``.. doxygenenum::`` + * Functions - ``.. doxygenfunction::`` + + See `Breathe documentation `_ for additional information. + + 4. Once done remove superfluous headers. + 5. When changes are committed and documentation is build, check how this section rendered. :doc:`Correct annotations <../documenting-code>` in respective header files, if required. + +Header Files +^^^^^^^^^^^^ + + * `path/header-file.h` + +Data Structures +^^^^^^^^^^^^^^^ + +:: + + .. doxygenstruct:: name_of_structure + :members: + +Macros +^^^^^^ + +:: + + .. doxygendefine:: name_of_macro + +Type Definitions +^^^^^^^^^^^^^^^^ + +:: + + .. doxygentypedef:: name_of_type + +Enumerations +^^^^^^^^^^^^ + +:: + + .. doxygenenum:: name_of_enumeration + +Functions +^^^^^^^^^ + +:: + + .. doxygenfunction:: name_of_function + + diff --git a/docs/api/uart.rst b/docs/api/uart.rst new file mode 100644 index 0000000000..609816fd46 --- /dev/null +++ b/docs/api/uart.rst @@ -0,0 +1,98 @@ +UART +==== + +Overview +-------- + +`Instructions`_ + +Application Example +------------------- + +`Instructions`_ + +API Reference +------------- + +`Instructions`_ + +.. _Instructions: template.html + +Header Files +^^^^^^^^^^^^ + + * `driver/include/driver/uart.h `_ + +Data Structures +^^^^^^^^^^^^^^^ + +.. doxygenstruct:: uart_config_t + :members: + +.. doxygenstruct:: uart_intr_config_t + :members: + +.. doxygenstruct:: uart_event_t + :members: + +Macros +^^^^^^ + +.. doxygendefine:: UART_FIFO_LEN +.. doxygendefine:: UART_INTR_MASK +.. doxygendefine:: UART_LINE_INV_MASK +.. doxygendefine:: UART_BITRATE_MAX +.. doxygendefine:: UART_PIN_NO_CHANGE +.. doxygendefine:: UART_INVERSE_DISABLE +.. doxygendefine:: UART_INVERSE_RXD +.. doxygendefine:: UART_INVERSE_CTS +.. doxygendefine:: UART_INVERSE_TXD +.. doxygendefine:: UART_INVERSE_RTS + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: uart_word_length_t +.. doxygenenum:: uart_stop_bits_t +.. doxygenenum:: uart_port_t +.. doxygenenum:: uart_parity_t +.. doxygenenum:: uart_hw_flowcontrol_t +.. doxygenenum:: uart_event_type_t + +Functions +^^^^^^^^^ + +.. doxygenfunction:: uart_set_word_length +.. doxygenfunction:: uart_get_word_length +.. doxygenfunction:: uart_set_stop_bits +.. doxygenfunction:: uart_get_stop_bits +.. doxygenfunction:: uart_set_parity +.. doxygenfunction:: uart_get_parity +.. doxygenfunction:: uart_set_baudrate +.. doxygenfunction:: uart_get_baudrate +.. doxygenfunction:: uart_set_line_inverse +.. doxygenfunction:: uart_set_hw_flow_ctrl +.. doxygenfunction:: uart_get_hw_flow_ctrl +.. doxygenfunction:: uart_clear_intr_status +.. doxygenfunction:: uart_enable_intr_mask +.. doxygenfunction:: uart_disable_intr_mask +.. doxygenfunction:: uart_enable_rx_intr +.. doxygenfunction:: uart_disable_rx_intr +.. doxygenfunction:: uart_disable_tx_intr +.. doxygenfunction:: uart_enable_tx_intr +.. doxygenfunction:: uart_isr_register +.. doxygenfunction:: uart_set_pin +.. doxygenfunction:: uart_set_rts +.. doxygenfunction:: uart_set_dtr +.. doxygenfunction:: uart_param_config +.. doxygenfunction:: uart_intr_config +.. doxygenfunction:: uart_driver_install +.. doxygenfunction:: uart_driver_delete +.. doxygenfunction:: uart_wait_tx_done +.. doxygenfunction:: uart_tx_chars +.. doxygenfunction:: uart_write_bytes +.. doxygenfunction:: uart_write_bytes_with_break +.. doxygenfunction:: uart_read_bytes +.. doxygenfunction:: uart_flush + + diff --git a/docs/api/vfs.rst b/docs/api/vfs.rst new file mode 100644 index 0000000000..df6cd03f67 --- /dev/null +++ b/docs/api/vfs.rst @@ -0,0 +1,43 @@ +.. include:: ../../components/vfs/README.rst + +Application Example +------------------- + +`Instructions `_ + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * `vfs/include/esp_vfs.h `_ + * `vfs/include/esp_vfs_dev.h `_ + +Macros +^^^^^^ + +.. doxygendefine:: ESP_VFS_PATH_MAX +.. doxygendefine:: ESP_VFS_FLAG_DEFAULT +.. doxygendefine:: ESP_VFS_FLAG_CONTEXT_PTR + +Structures +^^^^^^^^^^ + +.. doxygenstruct:: esp_vfs_t + +Functions +^^^^^^^^^ + +.. doxygenfunction:: esp_vfs_register +.. doxygenfunction:: esp_vfs_write +.. doxygenfunction:: esp_vfs_lseek +.. doxygenfunction:: esp_vfs_read +.. doxygenfunction:: esp_vfs_open +.. doxygenfunction:: esp_vfs_close +.. doxygenfunction:: esp_vfs_fstat +.. doxygenfunction:: esp_vfs_stat +.. doxygenfunction:: esp_vfs_link +.. doxygenfunction:: esp_vfs_unlink +.. doxygenfunction:: esp_vfs_rename +.. doxygenfunction:: esp_vfs_dev_uart_register diff --git a/docs/build_system.rst b/docs/build_system.rst index 4df65b1b5c..8168cb76ef 100644 --- a/docs/build_system.rst +++ b/docs/build_system.rst @@ -1,5 +1,5 @@ Build System ------------- +************ This document explains the Espressif IoT Development Framework build system and the concept of "components" @@ -8,262 +8,380 @@ Read this document if you want to know how to organise a new ESP-IDF project. We recommend using the esp-idf-template_ project as a starting point for your project. +Using the Build System +====================== + +The esp-idf README file contains a description of how to use the build system to build your project. + Overview ======== -An ESP-IDF project can be seen as an almagation of a number of components. -For example, for a webserver that shows the current humidity, we would -have: +An ESP-IDF project can be seen as an amalgamation of a number of components. +For example, for a webserver that shows the current humidity, there could be: - The ESP32 base libraries (libc, rom bindings etc) - The WiFi drivers - A TCP/IP stack - The FreeRTOS operating system - A webserver -- A driver for an humidity sensor +- A driver for the humidity sensor - Main code tying it all together -ESP-IDF makes these components explicit and configurable. To do that, when a project -is compiled, the build environment will look up all the components in the -ESP-IDF directories, the project directories and optionally custom other component -directories. It then allows the user to configure compile-time options using -a friendly text-based menu system to customize the ESP-IDF as well as other components -to the requirements of the project. After the components are customized, the -build process will compile everything into an output file, which can then be uploaded -into a board in a way that can also be defined by components. +ESP-IDF makes these components explicit and configurable. To do that, +when a project is compiled, the build environment will look up all the +components in the ESP-IDF directories, the project directories and +(optionally) in additional custom component directories. It then +allows the user to configure the ESP-IDF project using a a text-based +menu system to customize each component. After the components in the +project are configured, the build process will compile the project. -A project in this sense is defined as a directory under which all the files required -to build it live, excluding the ESP-IDF files and the toolchain. A simple project -tree might look like this:: +Concepts +-------- - - myProject/ - build/ +- A "project" is a directory that contains all the files and configuration to build a single "app" (executable), as well as additional supporting output such as a partition table, data/filesystem partitions, and a bootloader. + +- "Project configuration" is held in a single file called sdkconfig in the root directory of the project. This configuration file is modified via ``make menuconfig`` to customise the configuration of the project. A single project contains exactly one project configuration. + +- An "app" is an executable which is built by esp-idf. A single project will usually build two apps - a "project app" (the main executable, ie your custom firmware) and a "bootloader app" (the initial bootloader program which launches the project app). + +- "components" are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by esp-idf itself, others may be sourced from other places. + +Some things are not part of the project: + +- "ESP-IDF" is not part of the project. Instead it is standalone, and linked to the project via the ``IDF_PATH`` environment variable which holds the path of the ``esp-idf`` directory. This allows the IDF framework to be decoupled from your project. + +- The toolchain for compilation is not part of the project. The toolchain should be installed in the system command line PATH, or the path to the toolchain can be set as part of the compiler prefix in the project configuration. + + +Example Project +--------------- + +An example project directory tree might look like this:: + - myProject/ + - Makefile + - sdkconfig - components/ - component1/ - component.mk - Kconfig - src1.c - component2/ - component.mk - Kconfig - src1.c + - include/ + - component2.h - main/ - src1.c - src2.c - - Makefile + - component.mk + - build/ -As we can see, a project consists of a components/ subdirectory containing its -components as well as one or more directories containing the project-specific -sources; by default a single directory called 'main' is assumed. The project -directory will also have a Makefile where the projects name as well as optionally -other options are defined. After compilation, the project directory will contain -a 'build'-directory containing all of the objects, libraries and other generated -files as well as the final binary. +This example "myProject" contains the following elements: -Components also have a custom makefile - ``component.mk``. This contains various definititions -influencing the build process of the component as well as the project it's used -in. Components may also include a Kconfig file defining the compile-time options that are -settable by means of the menu system. +- A top-level project Makefile. This Makefile set the ``PROJECT_NAME`` variable and (optionally) defines + other project-wide make variables. It includes the core ``$(IDF_PATH)/make/project.mk`` makefile which + implements the rest of the ESP-IDF build system. -Project Makefile variables that can be set by the programmer:: +- "sdkconfig" project configuration file. This file is created/updated when "make menuconfig" runs, and holds configuration for all of the components in the project (including esp-idf itself). The "sdkconfig" file may or may not be added to the source control system of the project. - PROJECT_NAME: Mandatory. Name for the project - BUILD_DIR_BASE: Set the directory where all objects/libraries/binaries end up in. - Defaults to $(PROJECT_PATH)/build - COMPONENT_DIRS: Search path for components. Defaults to the component/ directories - in the ESP-IDF path and the project path. - COMPONENTS: A list of component names. Defaults to all the component found in the - COMPONENT_DIRS directory - EXTRA_COMPONENT_DIRS: Defaults to unset. Use this to add directories to the default - COMPONENT_DIRS. - SRCDIRS: Directories under the project dir containing project-specific sources. - Defaults to 'main'. These are treated as 'lite' components: they do not have - include directories that are passed to the compilation pass of all components and - they do not have a Kconfig option. +- Optional "components" directory contains components that are part of the project. A project does not have to contain custom components of this kind, but it can be useful for structuring reusable code or including third party components that aren't part of ESP-IDF. -Component-specific component.mk variables that can be set by the programmer:: +- "main" directory is a special "pseudo-component" that contains source code for the project itself. "main" is a default name, the Makefile variable ``SRCDIRS`` defaults to this but can be set to look for pseudo-components in other directories. - COMPONENT_ADD_INCLUDEDIRS: Relative path to include directories to be added to - the entire project. If an include directory is only needed to compile this - specific component, don't add it here. - COMPONENT_PRIV_INCLUDEDIRS: Relative path to include directories that are only used - when compiling this specific component. - COMPONENT_DEPENDS: Names of any components that need to be compiled before this component. - COMPONENT_ADD_LDFLAGS: LD flags to add for the entire project. Defaults to -l$(COMPONENT_NAME). - Add libraries etc in the current directory as $(abspath libwhatever.a) - COMPONENT_EXTRA_INCLUDES: Any extra include paths used when compiling the component's - source files. These will be prefixed with '-I' and passed to the compiler. - Similar to COMPONENT_PRIV_INCLUDEDIRS, but these paths are passed as-is instead of - expanded relative to the component directory. - COMPONENT_SRCDIRS: Relative directories to look in for sources. Defaults to '.', the current - directory (the root of the component) only. Use this to specify any subdirectories. Note - that specifying this overwrites the default action of compiling everything in the - components root dir; to keep this behaviour please also add '.' as a directory in this - list. - COMPONENT_OBJS: Object files to compile. Defaults to the .o variants of all .c and .S files - that are found in COMPONENT_SRCDIRS. - COMPONENT_EXTRA_CLEAN: Files that are generated using rules in the components Makefile - that also need to be cleaned - COMPONENT_BUILDRECIPE: Recipe to build the component. Optional. Defaults to building all - COMPONENT_OBJS and linking them into lib(componentname).a - COMPONENT_CLEANRECIPE: Recipe to clean the component. Optional. Defaults to removing - all built objects and libraries. - COMPONENT_BUILD_DIR: Equals the cwd of the component build, which is the build dir - of the component (where all the .o etc files should be created). +- "build" directory is where build output is created. After the make process is run, this directory will contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code. -These variables are already set early on in the Makefile and the values in it will -be usable in component or project Makefiles:: +Component directories contain a component makefile - ``component.mk``. This may contain variable definitions +to control the build process of the component, and its integration into the overall project. See `Component Makefiles` for more details. - CC, LD, AR, OBJCOPY: Xtensa gcc tools - HOSTCC, HOSTLD etc: Host gcc tools - LDFLAGS, CFLAGS: Set to usable values as defined in ESP-IDF Makefile - PROJECT_NAME: Name of the project, as set in project makefile - PROJECT_PATH: Path to the root of the project folder - COMPONENTS: Name of the components to be included - CONFIG_*: All values set by 'make menuconfig' have corresponding Makefile variables. +Each component may also include a ``Kconfig`` file defining the `component configuration` options that can be set via the project configuration. Some components may also include ``Kconfig.projbuild`` and ``Makefile.projbuild`` files, which are special files for `overriding parts of the project`. -Inside your component's component.mk makefile, you can override or add to these variables -as necessary. The changes are isolated from other components (see Makefile.projbuild below -if you want to share these changes with all other components.) +Project Makefiles +----------------- -For components, there also are these defines:: +Each project has a single Makefile that contains build settings for the entire project. By default, the project Makefile can be quite minimal. - COMPONENT_PATH: Absolute path to the root of the source tree of the component we're - compiling - COMPONENT_LIBRARY: The full path to the static library the components compilation pass - is supposed to generate +Minimal Example Makefile +^^^^^^^^^^^^^^^^^^^^^^^^ -Make Process ------------- +:: + PROJECT_NAME := myProject + + include $(IDF_PATH)/make/project.mk -The Make process is always invoked from the project directory by the -user; invoking it anywhere else gives an error. This is what happens if -we build a binary: -The Makefile first determines how it was included. It figures out -various paths as well as the components available to it. It will also -collect the ldflags and includes that the components specify they need. -It does this by running a dummy make on the components with a "get_variable" -target that will output these values. +Mandatory Project Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Makefile will then create targets to build the lib*.a libraries of -all components and make the elf target depend on this. The main Makefile -invokes Make on the componen.mk of each components inside a sub-mke: this way -the components have full freedom to do whatever is necessary to build -the library without influencing other components. By default, the -component.mk includes the utility makefile $(IDF_PATH)/make/component_common.mk. -This provides default targets and configurations that will work -out-of-the-box for most projects. +- ``PROJECT_NAME``: Name of the project. Binary output files will use this name - ie myProject.bin, myProject.elf. -KConfig -------- +Optional Project Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^ -Each component can also have a Kconfig file, alongside the component.mk, that contains -details to add to "menuconfig" for this component. +These variables all have default values that can be overridden for custom behaviour. Look in ``make/project.mk`` for all of the implementation details. + +- ``PROJECT_PATH``: Top-level project directory. Defaults to the directory containing the Makefile. Many other project variables are based on this variable. The project path cannot contain spaces. +- ``BUILD_DIR_BASE``: The build directory for all objects/libraries/binaries. Defaults to ``$(PROJECT_PATH)/build``. +- ``COMPONENT_DIRS``: Directories to search for components. Defaults to `$(IDF_PATH)/components`, `$(PROJECT_PATH)/components` and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in the esp-idf & project ``components`` directories. +- ``EXTRA_COMPONENT_DIRS``: Optional list of additional directories to search for components. Components themselves are in sub-directories of these directories, this is a top-level directory containing the component directories. +- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the COMPONENT_DIRS directories. +- ``SRCDIRS``: Directories under the main project directory which contain project-specific "pseudo-components". Defaults to 'main'. The difference between specifying a directory here and specifying it under ``EXTRA_COMPONENT_DIRS`` is that a directory in ``SRCDIRS`` is a component itself (contains a file "component.mk"), whereas a directory in ``EXTRA_COMPONENT_DIRS`` contains component directories which contain a file "component.mk". See the `Example Project` for a concrete case of this. + + +Component Makefiles +------------------- + +Each project contains one or more components, which can either be part of esp-idf or added from other component directories. + +A component is any sub-directory that contains a `component.mk` file.[#f1]_. + +Minimal Component Makefile +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The minimal ``component.mk`` file is an empty file(!). If the file is empty, the default component behaviour is set: +- All source files in the same directory as the makefile (*.c, *.cpp, *.S) will be compiled into the component library +- A sub-directory "include" will be added to the global include search path for all other components. +- The component library will be linked into the project app. + +See `example component makefiles` for more complete component makefile examples. + +Note that there is a different between an empty ``component.mk`` file (which invokes default component build behaviour) and no ``component.mk`` file (which means no default component build behaviour will occur.) It is possible for a component to have no `component.mk` file, if it only contains other files which influence the project configuration or build process. + +.. component variables: + +Preset Component Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following component-specific variables are available for use inside ``component.mk``, but should not be modified: + +- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``component.mk``. The component path cannot contain spaces. +- ``COMPONENT_NAME``: Name of the component. Defaults to the name of the component directory. +- ``COMPONENT_BUILD_DIR``: The component build directory. Evaluates to the absolute path of a directory inside `$(BUILD_DIR_BASE)` where this component's source files are to be built. This is also the Current Working Directory any time the component is being built, so relative paths in make targets, etc. will be relative to this directory. +- ``COMPONENT_LIBRARY``: Name of the static library file (relative to the component build directory) that will be built for this component. Defaults to ``$(COMPONENT_NAME).a``. + +The following variables are set at the project level, but exported for use in the component build: + +- ``PROJECT_NAME``: Name of the project, as set in project Makefile +- ``PROJECT_PATH``: Absolute path of the project directory containing the project Makefile. +- ``COMPONENTS``: Name of all components that are included in this build. +- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in make. All names begin with ``CONFIG_``. +- ``CC``, ``LD``, ``AR``, ``OBJCOPY``: Full paths to each tool from the gcc xtensa cross-toolchain. +- ``HOSTCC``, ``HOSTLD``, ``HOSTAR``: Full names of each tool from the host native toolchain. + +If you modify any of these variables inside ``component.mk`` then this will not prevent other components from building but it may make your component hard to build and/or debug. + +Optional Project-Wide Component Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following variables can be set inside ``component.mk`` to control build settings across the entire project: + +- ``COMPONENT_ADD_INCLUDEDIRS``: Paths, relative to the component + directory, which will be added to the include search path for + all components in the project. Defaults to ``include`` if not overridden. If an include directory is only needed to compile + this specific component, add it to ``COMPONENT_PRIV_INCLUDEDIRS`` instead. +- ``COMPONENT_ADD_LDFLAGS``: Add linker arguments to the LDFLAGS for + the app executable. Defaults to ``-l$(COMPONENT_NAME)``. If + adding pre-compiled libraries to this directory, add them as + absolute paths - ie $(COMPONENT_PATH)/libwhatever.a +- ``COMPONENT_DEPENDS``: Optional list of component names that should + be compiled before this component. This is not necessary for + link-time dependencies, because all component include directories + are available at all times. It is necessary if one component + generates an include file which you then want to include in another + component. Most components do not need to set this variable. + + +Optional Component-Specific Variables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following variables can be set inside ``component.mk`` to control the build of that component: + +- ``COMPONENT_PRIV_INCLUDEDIRS``: Directory paths, must be relative to + the component directory, which will be added to the include search + path for this component's source files only. +- ``COMPONENT_EXTRA_INCLUDES``: Any extra include paths used when + compiling the component's source files. These will be prefixed with + '-I' and passed as-is to the compiler. Similar to the + ``COMPONENT_PRIV_INCLUDEDIRS`` variable, except these paths are not + expanded relative to the component directory. +- ``COMPONENT_SRCDIRS``: Directory paths, must be relative to the + component directory, which will be searched for source files (*.cpp, + *.c, *.S). Defaults to '.', ie the component directory + itself. Override this to specify a different list of directories + which contain source files. +- ``COMPONENT_OBJS``: Object files to compile. Default value is a .o + file for each source file that is found in ``COMPONENT_SRCDIRS``. + Overriding this list allows you to exclude source files in + ``COMPONENT_SRCDIRS`` that would otherwise be compiled. See + `Specifying source files` +- ``COMPONENT_EXTRA_CLEAN``: Paths, relative to the component build + directory, of any files that are generated using custom make rules + in the component.mk file and which need to be removed as part of + ``make clean``. See `Source Code Generation` for an example. +- ``COMPONENT_OWNBUILDTARGET`` & `COMPONENT_OWNCLEANTARGET`: These + targets allow you to fully override the default build behaviour for + the component. See `Fully Overriding The Component Makefile` for + more details. +- ``CFLAGS``: Flags passed to the C compiler. A default set of + ``CFLAGS`` is defined based on project settings. Component-specific + additions can be made via ``CFLAGS +=``. It is also possible + (although not recommended) to override this variable completely for + a component. +- ``CPPFLAGS``: Flags passed to the C preprocessor (used for .c, .cpp + and .S files). A default set of ``CPPFLAGS`` is defined based on + project settings. Component-specific additions can be made via + ``CPPFLAGS +=``. It is also possible (although not recommended) to + override this variable completely for a component. +- ``CXXFLAGS``: Flags passed to the C++ compiler. A default set of + ``CXXFLAGS`` is defined based on project + settings. Component-specific additions can be made via ``CXXFLAGS + +=``. It is also possible (although not recommended) to override + this variable completely for a component. + +Component Configuration +----------------------- + +Each component can also have a Kconfig file, alongside ``component.mk``. This contains contains +configuration settings to add to the "make menuconfig" for this component. + +These settings are found under the "Component Settings" menu when menuconfig is run. + +To create a component KConfig file, it is easiest to start with one of the KConfig files distributed with esp-idf. + +For an example, see `Adding conditional configuration`. + +Build Process Internals +----------------------- + +Top Level: Project Makefile +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- "make" is always run from the project directory and the project makefile, typically named Makefile. +- The project makefile sets ``PROJECT_NAME`` and optionally customises other `optional project variables` +- The project makefile includes ``$(IDF_PATH)/make/project.mk`` which contains the project-level Make logic. +- ``project.mk`` fills in default project-level make variables and includes make variables from the project configuration. If the generated makefile containing project configuration is out of date, then it is regenerated (via targets in ``project_config.mk``) and then the make process restarts from the top. +- ``project.mk`` builds a list of components to build, based on the default component directories or a custom list of components set in `optional project variables`. +- Each component can set some `optional project-wide component variables`. These are included via generated makefiles named ``component_project_vars.mk`` - there is one per component. These generated makefiles are included into ``project.mk``. If any are missing or out of date, they are regenerated (via a recursive make call to the component makefile) and then the make process restarts from the top. +- `Makefile.projbuild` files from components are included into the make process, to add extra targets or configuration. +- By default, the project makefile also generates top-level build & clean targets for each component and sets up `app` and `clean` targets to invoke all of these sub-targets. +- In order to compile each component, a recursive make is performed for the component makefile. + +To better understand the project make process, have a read through the ``project.mk`` file itself. + +Second Level: Component Makefiles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Each call to a component makefile goes via the ``$(IDF_PATH)/make/component_wrapper.mk`` wrapper makefile. +- The ``component_wrapper.mk`` is called with the current directory set to the component build directory, and the ``COMPONENT_MAKEFILE`` variable is set to the absolute path to ``component.mk``. +- ``component_wrapper.mk`` sets default values for all `component variables`, then includes the `component.mk` file which can override or modify these. +- If ``COMPONENT_OWNBUILDTARGET`` and ``COMPONENT_OWNCLEANTARGET`` are not defined, default build and clean targets are created for the component's source files and the prerequisite ``COMPONENT_LIBRARY`` static library file. +- The ``component_project_vars.mk`` file has its own target in ``component_wrapper.mk``, which is evaluated from ``project.mk`` if this file needs to be rebuilt due to changes in the component makefile or the project configuration. + +To better understand the component make process, have a read through the ``component_wrapper.mk`` file and some of the ``component.mk`` files included with esp-idf. + +Debugging The Make Process +-------------------------- + +Some tips for debugging the esp-idf build system: + +- Appending ``V=1`` to the make arguments (or setting it as an environment variable) will cause make to echo all commands executed, and also each directory as it is entered for a sub-make. +- Running ``make -w`` will cause make to echo each directory as it is entered for a sub-make - same as ``V=1`` but without also echoing all commands. +- Running ``make --trace`` (possibly in addition to one of the above arguments) will print out every target as it is built, and the dependency which caused it to be built. +- Running ``make -p`` prints a (very verbose) summary of every generated target in each makefile. + +For more debugging tips and general make information, see the `GNU Make Manual`. + +Overriding Parts of the Project +------------------------------- Makefile.projbuild ------------------- +^^^^^^^^^^^^^^^^^^ -For components that have parts that need to be evaluated in the top-level -project context, you can create a file called Makefile.projbuild in the -component root directory. These files is included into the project's -top-level Makefile. +For components that have build requirements that must be evaluated in the top-level +project make pass, you can create a file called ``Makefile.projbuild`` in the +component directory. This makefile is included when ``project.mk`` is evaluated. For example, if your component needs to add to CFLAGS for the entire project (not just for its own source files) then you can set -``CFLAGS +=`` in Makefile.projbuild. Note that this isn't necessary for -adding include directories to the project, you can set -``COMPONENT_ADD_INCLUDEDIRS`` (see above) in the component.mk. +``CFLAGS +=`` in Makefile.projbuild. +``Makefile.projbuild`` files are used heavily inside esp-idf, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". + +Note that ``Makefile.projbuild`` isn't necessary for the most common component uses - such as adding include directories to the project, or LDFLAGS to the final linking step. These values can be customised via the ``component.mk`` file itself. See `Optional Project-Wide Component Variables` for details. + +Take care when setting variables or targets in this file. As the values are included into the top-level project makefile pass, they can influence or break functionality across all components! KConfig.projbuild ------------------ +^^^^^^^^^^^^^^^^^ -There's an equivalent to Makefile.projbuild for KConfig: if you want to include -options at the top-level, not inside the 'components' submenu then create a Kconfig.projbuild and -it will be included in the main menu of menuconfig. +This is an equivalent to `Makefile.projbuild` for `component configuration` KConfig files. If you want to include +configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``component.mk`` file. -Take good care when (re)defining stuff here: because it's included with all the other -.projbuild files, it's possible to overwrite variables or re-declare targets defined in -the ESP-IDF makefile/Kconfig and other .projbuild files. It's generally better to just -create a KConfig file, if you can. +Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for `component configuration`. -Writing Component Makefiles +Example Component Makefiles --------------------------- -A component consists of a directory which doubles as the name for the -component: a component named 'httpd' lives in a directory called 'httpd' -Because components usually live under the project directory (although -they can also reside in an other folder), the path to this may be -something like /home/myuser/projects/myprojects/components/httpd . +Because the build environment tries to set reasonable defaults that will work most +of the time, component.mk can be very small or even empty (see `Minimal Component Makefile`). However, overriding `component variables` is usually required for some functionality. -Components can have any name (unique to the project) but the name -cannot contain spaces (esp-idf does not support spaces in paths). - -One of the things that most components will have is a component.mk makefile, -containing instructions on how to build the component. Because the -build environment tries to set reasonable defaults that will work most -of the time, component.mk can be very small. - -Simplest component.mk -===================== - -At the minimum, component.mk will just include the ESP-IDF component "common" makefile, -which adds common component functionality:: - - include $(IDF_PATH)/make/component_common.mk - -This will take all the .c and .S files in the component root and compile -them into object files, finally linking them into a library. +Here are some more advanced examples of ``component.mk`` makefiles: Adding source directories -========================= +^^^^^^^^^^^^^^^^^^^^^^^^^ -By default, subdirectories are ignored. If your project has sources in subdirectories +By default, sub-directories are ignored. If your project has sources in sub-directories instead of in the root of the component then you can tell that to the build -system by setting COMPONENT_SRCDIRS:: +system by setting ``COMPONENT_SRCDIRS``:: COMPONENT_SRCDIRS := src1 src2 - include $(IDF_PATH)/make/component_common.mk -This will compile all source files in the src1/ and src2/ subdirectories +This will compile all source files in the src1/ and src2/ sub-directories instead. Specifying source files -======================= +^^^^^^^^^^^^^^^^^^^^^^^ The standard component.mk logic adds all .S and .c files in the source directories as sources to be compiled unconditionally. It is possible -to circumvent that logic and hardcode the objects to be compiled by -manually setting the COMPONENT_OBJS variable to the name of the +to circumvent that logic and hard-code the objects to be compiled by +manually setting the ``COMPONENT_OBJS`` variable to the name of the objects that need to be generated:: COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o - include $(IDF_PATH)/make/component_common.mk + COMPONENT_SRCDIRS := . thing anotherthing +Note that ``COMPONENT_SRCDIRS`` must be set as well. Adding conditional configuration -================================ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The configuration system can be used to conditionally compile some files -dependending on the options selected in ``make menuconfig``: +depending on the options selected in ``make menuconfig``: -Kconfig:: +``Kconfig``:: config FOO_ENABLE_BAR - bool "Enable the BAR feature." - help - This enables the BAR feature of the FOO component. + bool "Enable the BAR feature." + help + This enables the BAR feature of the FOO component. -Makefile:: - COMPONENT_OBJS := foo_a.o foo_b.o $(if $(CONFIG_FOO_ENABLE_BAR),foo_bar.o foo_bar_interface.o) - include $(IDF_PATH)/make/component_common.mk +``component.mk``:: + COMPONENT_OBJS := foo_a.o foo_b.o + + ifdef CONFIG_FOO_BAR + COMPONENT_OBJS += foo_bar.o foo_bar_interface.o + endif + +See the `GNU Make Manual` for conditional syntax that can be used use in makefiles. Source Code Generation -====================== +^^^^^^^^^^^^^^^^^^^^^^ -Some components will have a situation where a source file isn't supplied -with the component itself but has to be generated from another file. Say -our component has a header file that consists of the converted binary -data of a BMP file, converted using a hypothetical tool called bmp2h. The -header file is then included in as C source file called graphics_lib.c:: +Some components will have a situation where a source file isn't +supplied with the component itself but has to be generated from +another file. Say our component has a header file that consists of the +converted binary data of a BMP file, converted using a hypothetical +tool called bmp2h. The header file is then included in as C source +file called graphics_lib.c:: COMPONENT_EXTRA_CLEAN := logo.h @@ -272,7 +390,6 @@ header file is then included in as C source file called graphics_lib.c:: logo.h: $(COMPONENT_PATH)/logo.bmp bmp2h -i $^ -o $@ - include $(IDF_PATH)/make/component_common.mk In this example, graphics_lib.o and logo.h will be generated in the current directory (the build directory) while logo.bmp comes with the @@ -281,24 +398,42 @@ generated file, it needs to be cleaned when make clean is called which why it is added to the COMPONENT_EXTRA_CLEAN variable. Cosmetic Improvements -===================== +^^^^^^^^^^^^^^^^^^^^^ -The above example will work just fine, but there's one last cosmetic -improvement that can be done. The make system tries to make the make -process somewhat easier on the eyes by hiding the commands (unless you -run make with the V=1 switch) and this does not do that yet. Here's an -improved version that will output in the same style as the rest of the -make process:: +Because logo.h is a generated file, it needs to be cleaned when make +clean is called which why it is added to the COMPONENT_EXTRA_CLEAN +variable. - COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h +Adding logo.h to the ``graphics_lib.o`` dependencies causes it to be +generated before ``graphics_lib.c`` is compiled. - graphics_lib.o: logo.h +If a a source file in another component included ``logo.h``, then this +component's name would have to be added to the other component's +``COMPONENT_DEPENDS`` list to ensure that the components were built +in-order. - logo.h: $(COMPONENT_PATH)/logo.bmp - $(summary) BMP2H $@ - $(Q) bmp2h -i $^ -o $@ +Embedding Binary Data +^^^^^^^^^^^^^^^^^^^^^ + +Sometimes you have a file with some binary or text data that you'd like to make available to your component - but you don't want to reformat the file as C source. + +You can set a variable COMPONENT_EMBED_FILES in component.mk, giving the names of the files to embed in this way:: + + COMPONENT_EMBED_FILES := server_root_cert.der + +Or if the file is a string, you can use the variable COMPONENT_EMBED_TXTFILES. This will embed the contents of the text file as a null-terminated string:: + + COMPONENT_EMBED_TXTFILES := server_root_cert.pem + +The file's contents will be added to the .rodata section in flash, and are available via symbol names as follows:: + + extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start"); + extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end"); + +The names are generated from the full name of the file, as given in COMPONENT_EMBED_FILES. Characters /, ., etc. are replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for both text and binary files. + +For an example of using this technique, see examples/04_https_request - the certificate file contents are loaded from the text .pem file at compile time. - include $(IDF_PATH)/make/component_common.mk Fully Overriding The Component Makefile --------------------------------------- @@ -307,12 +442,15 @@ Obviously, there are cases where all these recipes are insufficient for a certain component, for example when the component is basically a wrapper around another third-party component not originally intended to be compiled under this build system. In that case, it's possible to forego -the build system entirely by setting COMPONENT_OWNBUILDTARGET and -possibly COMPONENT_OWNCLEANTARGET and defining your own build- and clean +the esp-idf build system entirely by setting COMPONENT_OWNBUILDTARGET and +possibly COMPONENT_OWNCLEANTARGET and defining your own targets named ``build`` and ``clean`` in ``component.mk`` target. The build target can do anything as long as it creates -$(COMPONENT_LIBRARY) for the main file to link into the project binary, -and even that is not necessary: if the COMPONENT_ADD_LDFLAGS variable -is set, the component can instruct the linker to do anything else as well. +$(COMPONENT_LIBRARY) for the project make process to link into the app binary. + +(Actually, even this is not strictly necessary - if the COMPONENT_ADD_LDFLAGS variable +is set then the component can instruct the linker to link other binaries instead.) .. _esp-idf-template: https://github.com/espressif/esp-idf-template +.. _GNU Make Manual: https://www.gnu.org/software/make/manual/make.html +.. _[_f1]: Actually, some components in esp-idf are "pure configuration" components that don't have a component.mk file, only a Makefile.projbuild and/or Kconfig.projbuild file. However, these components are unusual and most components have a component.mk file. diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000..551cd86dd0 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,306 @@ +# -*- coding: utf-8 -*- +# +# Read the Docs Template documentation build configuration file, created by +# sphinx-quickstart on Tue Aug 26 14:19:49 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- Run DoxyGen to prepare XML for Sphinx--------------------------------- +# ref. https://github.com/rtfd/readthedocs.org/issues/388 + +from subprocess import call, Popen, PIPE +import shlex + +call('doxygen') + +# -- Function to get output of a command ---------------------------------- +def run_cmd_get_output(cmd): + process = Popen(shlex.split(cmd), stdout=PIPE) + (output, err) = process.communicate() + exit_code = process.wait() + if exit_code != 0: + raise RuntimeError('command line program has failed') + return output + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['breathe'] + +# Breathe extension variables +breathe_projects = { "esp32-idf": "xml/" } +breathe_default_project = "esp32-idf" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'ESP32 Programming Guide' +copyright = u'2016, Espressif' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# + +# Different setup depending if script is running on ReadTheDocs or elsewhere +on_rtd = os.environ.get('READTHEDOCS') == 'True' +if on_rtd: + # The short X.Y version. + # Apparently ReadTheDocs is getting confused by other version / release + # ReadTheDocs is building specific or the latest release from GitHub. + version = '1.0' + release = '1.0' +else: + # This is supposed to be "the short X.Y version", but it's the only version + # visible when you open index.html. + # Display full version to make things less confusing. + # If needed, nearest tag is returned by 'git describe --abbrev=0'. + version = run_cmd_get_output('git describe') + # The full version, including alpha/beta/rc tags. + release = run_cmd_get_output('git describe') + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'ReadtheDocsTemplatedoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'ReadtheDocsTemplate.tex', u'Read the Docs Template Documentation', + u'Read the Docs', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'readthedocstemplate', u'Read the Docs Template Documentation', + [u'Read the Docs'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'ReadtheDocsTemplate', u'Read the Docs Template Documentation', + u'Read the Docs', 'ReadtheDocsTemplate', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +# -- Use sphinx_rtd_theme for local builds -------------------------------- +# ref. https://github.com/snide/sphinx_rtd_theme#using-this-theme-locally-then-building-on-read-the-docs +# +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# otherwise, readthedocs.org uses their theme by default, so no need to specify it diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 0000000000..3bdd7dc21a --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1 @@ +.. include:: ../CONTRIBUTING.rst \ No newline at end of file diff --git a/docs/contributor-agreement.rst b/docs/contributor-agreement.rst index 7c194e7728..a7919da8f8 100644 --- a/docs/contributor-agreement.rst +++ b/docs/contributor-agreement.rst @@ -1,5 +1,5 @@ Contributor Agreement ---------------------- +===================== Individual Contributor Non-Exclusive License Agreement ------------------------------------------------------ @@ -13,7 +13,7 @@ Framework (esp-idf) ("We" or "Us"). The purpose of this contributor agreement ("Agreement") is to clarify and document the rights granted by contributors to Us. To make this document effective, please follow the instructions at -https://github.com/espressif/esp-idf/blob/master/CONTRIBUTING.md. +https://github.com/espressif/esp-idf/blob/master/CONTRIBUTING.rst. 1. DEFINITIONS ~~~~~~~~~~~~~~ diff --git a/docs/deep-sleep-stub.rst b/docs/deep-sleep-stub.rst new file mode 100644 index 0000000000..7711b1ce23 --- /dev/null +++ b/docs/deep-sleep-stub.rst @@ -0,0 +1,87 @@ +Deep Sleep Wake Stubs +===================== + +ESP32 supports running a "deep sleep wake stub" when coming out of deep sleep. This function runs immediately as soon as the chip wakes up - before any normal initialisation, bootloader, or ESP-IDF code has run. After the wake stub runs, the SoC can go back to sleep or continue to start ESP-IDF normally. + +Deep sleep wake stub code is loaded into "RTC Fast Memory" and any data which it uses must also be loaded into RTC memory. RTC memory regions hold their contents during deep sleep. + +Rules for Wake Stubs +-------------------- + +Wake stub code must be carefully written: + +* As the SoC has freshly woken from sleep, most of the peripherals are in reset states. The SPI flash is unmapped. + +* The wake stub code can only call functions implemented in ROM or loaded into RTC Fast Memory (see below.) + +* The wake stub code can only access data loaded in RTC memory. All other RAM will be unintiailised and have random contents. The wake stub can use other RAM for temporary storage, but the contents will be overwritten when the SoC goes back to sleep or starts ESP-IDF. + +* RTC memory must include any read-only data (.rodata) used by the stub. + +* Data in RTC memory is initialised whenever the SoC restarts, except when waking from deep sleep. When waking from deep sleep, the values which were present before going to sleep are kept. + +* Wake stub code is a part of the main esp-idf app. During normal running of esp-idf, functions can call the wake stub functions or access RTC memory. It is as if these were regular parts of the app. + +Implementing A Stub +------------------- + +The wake stub in esp-idf is called ``esp_wake_deep_sleep()``. This function runs whenever the SoC wakes from deep sleep. There is a default version of this function provided in esp-idf, but the default function is weak-linked so if your app contains a function named ``esp_wake_deep_sleep()`` then this will override the default. + +If supplying a custom wake stub, the first thing it does should be to call ``esp_default_wake_deep_sleep()``. + +It is not necessary to implement ``esp_wake_deep_sleep()`` in your app in order to use deep sleep. It is only necessary if you want to have special behaviour immediately on wake. + +If you want to swap between different deep sleep stubs at runtime, it is also possible to do this by calling the ``esp_set_deep_sleep_wake_stub()`` function. This is not necessary if you only use the default ``esp_wake_deep_sleep()`` function. + +All of these functions are declared in the ``esp_deepsleep.h`` header under components/esp32. + +Loading Code Into RTC Memory +---------------------------- + +Wake stub code must be resident in RTC Fast Memory. This can be done in one of two ways. + +The first way is to use the ``RTC_IRAM_ATTR`` attribute to place a function into RTC memory:: + + void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { + esp_default_wake_deep_sleep(); + // Add additional functionality here + } + +The second way is to place the function into any source file whose name starts with ``rtc_wake_stub``. Files names ``rtc_wake_stub*`` have their contents automatically put into RTC memory by the linker. + +The first way is simpler for very short and simple code, or for source files where you want to mix "normal" and "RTC" code. The second way is simpler when you want to write longer pieces of code for RTC memory. + + +Loading Data Into RTC Memory +---------------------------- + +Data used by stub code must be resident in RTC Slow Memory. This memory is also used by the ULP. + +Specifying this data can be done in one of two ways: + +The first way is to use the ``RTC_DATA_ATTR`` and ``RTC_RODATA_ATTR`` to specify any data (writeable or read-only, respectivley) which should be loaded into RTC slow memory:: + + RTC_DATA_ATTR int wake_count; + + void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { + esp_default_wake_deep_sleep(); + static RTC_RODATA_ATTR const char fmt_str[] = "Wake count %d\n"; + ets_printf(fmt_str, wake_count++); + } + +Unfortunately, any string constants used in this way must be declared as arrays and marked with RTC_RODATA_ATTR, as shown in the example above. + +The second way is to place the data into any source file whose name starts with ``rtc_wake_stub``. + +For example, the equivalent example in ``rtc_wake_stub_counter.c``:: + + int wake_count; + + void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { + esp_default_wake_deep_sleep(); + ets_printf("Wake count %d\n", wake_count++); + } + +The second way is a better option if you need to use strings, or write other more complex code. + + diff --git a/docs/documenting-code.rst b/docs/documenting-code.rst new file mode 100644 index 0000000000..72e3cea147 --- /dev/null +++ b/docs/documenting-code.rst @@ -0,0 +1,159 @@ +Documenting Code +================ + +The purpose of this description is to provide quick summary on documentation style used in `espressif/esp-idf`_ repository and how to add new documentation. + +Introduction +------------ + +When documenting code for this repository, please follow `Doxygen style `_. You are doing it by inserting special commands, for instance ``@param``, into standard comments blocks, for example: + +:: + + /** + * @param ratio this is oxygen to air ratio + */ + +Doxygen is phrasing the code, extracting the commands together with subsequent text, and building documentation out of it. + +Typical comment block, that contains documentation of a function, looks like below. + +.. image:: _static/doc-code-documentation-inline.png + :align: center + :alt: Sample inline code documentation + +Doxygen supports couple of formatting styles. It also gives you great flexibility on level of details to include in documentation. To get familiar with available features, please check data reach and very well organized `Doxygen Manual `_. + +Why we need it? +--------------- + +The ultimate goal is to ensure that all the code is consistently documented, so we can use tools like `Sphinx `_ and `Breathe `_ to aid preparation and automatic updates of API documentation when the code changes. + +With these tools the above piece of code renders like below: + +.. image:: _static/doc-code-documentation-rendered.png + :align: center + :alt: Sample inline code after rendering + +Go for it! +---------- + +When writing code for this repository, please follow guidelines below. + + 1. Document all building blocks of code: functions, structs, typedefs, enums, macros, etc. Provide enough information on purpose, functionality and limitations of documented items, as you would like to see them documented when reading the code by others. + + 2. Documentation of function should describe what this function does. If it accepts input parameters and returns some value, all of them should be explained. + + 3. Do not add a data type before parameter or any other characters besides spaces. All spaces and line breaks are compressed into a single space. If you like to break a line, then break it twice. + + .. image:: _static/doc-code-function.png + :align: center + :alt: Sample function documented inline and after rendering + + 4. If function has void input or does not return any value, then skip ``@param`` or ``@return`` + + .. image:: _static/doc-code-void-function.png + :align: center + :alt: Sample void function documented inline and after rendering + + 5. When documenting members of a ``struct``, ``typedef`` or ``enum``, place specific comment like below after each member. + + .. image:: _static/doc-code-member.png + :align: center + :alt: Sample of member documentation inline and after rendering + + 6. To provide well formatted lists, break the line after command (like ``@return`` in example below). + + .. code-block:: c + + ... + * + * @return + * - ESP_OK if erase operation was successful + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - other error codes from the underlying storage driver + * + ... + + 7. Overview of functionality of documented header file, or group of files that make a library, should be placed in the same directory in a separate ``README.rst`` file. If directory contains header files for different APIs, then the file name should be ``apiname-readme.rst``. + +Go one extra mile +----------------- + +There is couple of tips, how you can make your documentation even better and more useful to the reader. + + 1. Add code snippets to illustrate implementation. To do so, enclose snippet using ``@code{c}`` and ``@endcode`` commands. + + .. code-block:: c + + ... + * + * @code{c} + * // Example of using nvs_get_i32: + * int32_t max_buffer_size = 4096; // default value + * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size); + * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND); + * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still + * // have its default value. + * @endcode + * + ... + + The code snippet should be enclosed in a comment block of the function that it illustrates. + + 2. To highlight some important information use command ``@attention`` or ``@note``. + + .. code-block:: c + + ... + * + * @attention + * 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode + * 2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect. + * + ... + + Above example also shows how to use a numbered list. + + 3. Use markdown to make your documentation even more readable. You will add headers, links, tables and more. + + .. code-block:: c + + ... + * + * [ESP32 Technical Reference](http://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf) + * + ... + + .. note:: + + Code snippets, notes, links, etc. will not make it to the documentation, if not enclosed in a comment block associated with one of documented objects. + + 5. Prepare one or more complete code examples together with description. Place them in a separate file ``example.rst`` in the same directory as the API header files. If directory contains header files for different APIs, then the file name should be ``apiname-example.rst``. + +Put it all together +------------------- + +Once all the above steps are complete, follow instruction in :doc:`api/template` and create a single file, that will merge all individual pieces of prepared documentation. Finally add a link to this file to respective ``.. toctree::`` in ``index.rst`` file located in ``/docs`` folder. + +OK, but I am new to Sphinx! +--------------------------- + +1. No worries. All the software you need is well documented. It is also open source and free. Start by checking `Sphinx `_ documentation. If you are not clear how to write using rst markup language, see `reStructuredText Primer `_. +2. Check the source files of this documentation to understand what is behind of what you see now on the screen. Sources are maintained on GitHub in `espressif/esp-idf`_ repository in `/docs `_ folder. You can go directly to the source file of this page by scrolling up and clicking the link in the top right corner. When on GitHub, see what's really inside, open source files by clicking ``Raw`` button. +3. You will likely want to see how documentation builds and looks like before posting it on the GitHub. There are two options to do so: + + * Install `Sphinx `_, `Breathe `_ and `Doxygen `_ to build it locally. You would need a Linux machine for that. + * Set up an account on `Read the Docs `_ and build documentation in the cloud. Read the Docs provides document building and hosting for free and their service works really quick and great. + +Wrap up +------- + +We love good code that is doing cool things. +We love it even better, if it is well documented, so we can quickly make it run and also do the cool things. + +Go ahead, contribute your code and documentation! + +.. _espressif/esp-idf: https://github.com/espressif/esp-idf/ diff --git a/docs/eclipse-setup.rst b/docs/eclipse-setup.rst index 21d83a7f06..fbad93be6c 100644 --- a/docs/eclipse-setup.rst +++ b/docs/eclipse-setup.rst @@ -1,3 +1,6 @@ +Build and Flash with Eclipse IDE +******************************** + Installing Eclipse IDE ====================== diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000000..1ca6e28eec --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,137 @@ +ESP32 Programming Guide +======================= + +.. caution:: + + Until ESP-IDF release 1.0, this documentation is a draft. It is incomplete and may have mistakes. Please mind your step! + +Contents: + +.. toctree:: + :caption: Setup Toolchain + :maxdepth: 1 + + Windows + Linux + Mac OS + +.. Connect - TBA + +.. toctree:: + :caption: Build and Flash + :maxdepth: 1 + + Make + Eclipse IDE + +.. toctree:: + :caption: What Else? + :maxdepth: 1 + + partition-tables + build_system + openocd + Secure Boot + +.. API Reference + .. + Table of Contents Outline + .. + 1. System - TBA + 1.1. Fundamentals of multiprocessor programming with FreeRTOS - TBA + 1.2. Application startup flow - TBA + 1.3. Flash encryption and secure boot: how they work and APIs - TBA + 1.4. Lower Power Coprocessor - TBA + 1.5. Watchdogs + 1.6. ... + 2. Memeory - TBA + 2.1. Memory layout of the application (IRAM/IROM, limitations of each) - TBA + 2.2. Flash layout and partitions - TBA + 2.3. Flash access APIs - TBA + 2.4. Partition APIs - TBA + 2.5. OTA mechanism (app partitions, OTA partition) and APIs - TBA + 2.6. ... + 3. Wi-Fi + 4. Bluetooth + 4.1. BT Classic - TBA + 4.2. BLE + 5. Ethernet - TBA + 6. Interfaces + 6.1. GPIO + 6.2. ADC - TBA + 6.3. DAC - TBA + 6.4. UART - TBA + 6.5. I2C - TBA + 6.6. I2S - TBA + 6.7. SPI - TBA + 6.8. CAN - TBA + 6.9. SD Controller - TBA + 6.10. Infrared - TBA + 6.11. Pulse Counter - TBA + 6.12. PWM - TBA + 6.13. LED PWM + 6.14. ... + 7. Sensors - TBA + 7.1. Hall Sensor - TBA + 7.2. Temperature Sensor - TBA + 7.3. Touch Sensor - TBA + 8. Protocols - TBA + 9. Components + 9.1. Logging + 9.2 Non-Volatile Storage + 9.3 Virtual Filesystem + 9.3. Http sever - TBA + 10. Applications - TBA + .. + API Dcoumentation Teamplate + .. + +.. toctree:: + :caption: API Reference + :maxdepth: 1 + + Wi-Fi + Bluetooth + + api/gpio + api/uart + api/ledc + + Logging + Non-Volatile Storage + Virtual Filesystem + deep-sleep-stub + + Template + +.. toctree:: + :caption: Technical Reference + + Technical Reference + +.. Resources - TBA + +.. toctree:: + :caption: Contribute + :maxdepth: 1 + + contributing + Style Guide + documenting-code + contributor-agreement + +.. toctree:: + :caption: Legal + :maxdepth: 1 + + COPYRIGHT + +.. About - TBA + + +Indices +======= + +* :ref:`genindex` +* :ref:`search` + diff --git a/docs/linux-setup.rst b/docs/linux-setup.rst index 13e1b3a9c0..cf5e78b63d 100644 --- a/docs/linux-setup.rst +++ b/docs/linux-setup.rst @@ -1,3 +1,6 @@ +Set up of Toolchain for Linux +***************************** + Step 0: Prerequisites ===================== diff --git a/docs/macos-setup.rst b/docs/macos-setup.rst index 8178a17ada..53c6fe54c8 100644 --- a/docs/macos-setup.rst +++ b/docs/macos-setup.rst @@ -1,3 +1,6 @@ +Set up of Toolchain for Mac OS +****************************** + Step 0: Prerequisites ===================== diff --git a/docs/make-project.rst b/docs/make-project.rst new file mode 100644 index 0000000000..e72bb81dd0 --- /dev/null +++ b/docs/make-project.rst @@ -0,0 +1,63 @@ +Build and Flash with Make +========================= + +Finding a project +----------------- + +As well as the `esp-idf-template `_ project mentioned in the setup guide, esp-idf comes with some example projects on github in the `examples `_ directory. + +Once you've found the project you want to work with, change to its directory and you can configure and build it: + +Configuring your project +------------------------ + +`make menuconfig` + +Compiling your project +---------------------- + +`make all` + +... will compile app, bootloader and generate a partition table based on the config. + +Flashing your project +--------------------- + +When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running: + +`make flash` + +This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `make menuconfig`. + +You don't need to run `make all` before running `make flash`, `make flash` will automatically rebuild anything which needs it. + +Compiling & Flashing Just the App +--------------------------------- + +After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table: + +* `make app` - build just the app. +* `make app-flash` - flash just the app. + +`make app-flash` will automatically rebuild the app if it needs it. + +(There's no downside to reflashing the bootloader and partition table each time, if they haven't changed.) + +The Partition Table +------------------- + +Once you've compiled your project, the "build" directory will contain a binary file with a name like "my_app.bin". This is an ESP32 image binary that can be loaded by the bootloader. + +A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x4000 in the flash. + +Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded. + +The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables: + +* "Single factory app, no OTA" +* "Factory app, two OTA definitions" + +In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table. + +For more details about :doc:`partition tables ` and how to create custom variations, view the :doc:`documentation `. + diff --git a/docs/openocd.rst b/docs/openocd.rst index 57ee93db4a..2dcb55f0c5 100644 --- a/docs/openocd.rst +++ b/docs/openocd.rst @@ -1,11 +1,14 @@ +Debugging +========= + OpenOCD setup for ESP32 ----------------------- -The ESP31 and ESP32 have two powerful Xtensa cores, allowing for a great deal of variety of program architectures. The FreeRTOS -OS that comes with ESP-IDF is capable multi-core pre-emptive multithreading, allowing for an intuitive way of writing software. +The ESP31 and ESP32 have two powerful Xtensa cores, allowing for a great variety of program architectures. The FreeRTOS +OS that comes with ESP-IDF is capable of multi-core pre-emptive multithreading, allowing for an intuitive way of writing software. The downside of the ease of programming is that debugging without the right tools is harder: figuring out a bug that is caused -by two threads, maybe even running simultaneously on two different CPU cures, can take a long time when all you have are printf +by two threads, maybe even running simultaneously on two different CPU cores, can take a long time when all you have are printf statements. A better and in many cases quicker way to debug such problems is by using a debugger, connected to the processors over a debug port. @@ -84,7 +87,7 @@ Connecting a debugger to OpenOCD OpenOCD should now be ready to accept gdb connections. If you have compiled the ESP32 toolchain using Crosstool-NG, or if you have downloaded a precompiled toolchain from the Espressif website, you should already have xtensa-esp32-elf-gdb, a version of gdb that can be used for this. First, make sure the project you want to debug is compiled and flashed -into the ESP32s SPI flash. Then, in a different console than OpenOCD is running in, invoke gdb. For example, for the +into the ESP32's SPI flash. Then, in a different console than OpenOCD is running in, invoke gdb. For example, for the template app, you would do this like such:: cd esp-idf-template diff --git a/docs/partition-tables.rst b/docs/partition-tables.rst index e0a39126b5..5f5911bd52 100644 --- a/docs/partition-tables.rst +++ b/docs/partition-tables.rst @@ -1,8 +1,13 @@ Partition Tables ----------------- +================ + +Overview +-------- A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x4000 in the flash. +Partition table length is 0xC00 bytes (maximum 95 partition table entries). If the partition table is signed due to `secure boot`, the signature is appended after the table data. + Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded. The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables: @@ -127,3 +132,6 @@ Flashing the partition table * ``make flash``: Will flash everything including the partition table. A manual flashing command is also printed as part of ``make partition_table``. + + +.. _secure boot: security/secure-boot.rst diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000000..debed28677 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,6 @@ +# This is a list of python packages used to generate documentation. This file is used with pip: +# pip install requirements.txt +# +sphinx +sphinx-rtd-theme +breathe diff --git a/docs/security/secure-boot.rst b/docs/security/secure-boot.rst new file mode 100644 index 0000000000..bdc1b71699 --- /dev/null +++ b/docs/security/secure-boot.rst @@ -0,0 +1,179 @@ +Secure Boot +=========== + +Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset. + +Secure Boot is separate from the Encrypted Flash feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment. + +**IMPORTANT: As Encrypted Flash feature and related security features are not yet released, Secure Boot should not be considered sufficient for a secure device and we strongly recommend not enabling the one-time secure bootloader feature until it is mature.** + +Background +---------- + +- Most data is stored in flash. Flash access does not need to be protected from physical access in order for secure boot to function, because critical data is stored (non-software-accessible) in Efuses internal to the chip. + +- Efuses are used to store the secure bootloader key (in efuse block 2), and also a single Efuse bit (ABS_DONE_0) is burned (written to 1) to permanently enable secure boot on the chip. For more details about efuse, see the (forthcoming) chapter in the Technical Reference Manual. + +- To understand the secure boot process, first familiarise yourself with the standard `esp-idf boot process`. + +- Both stages of the boot process (initial software bootloader load, and subsequent partition & app loading) are verified by the secure boot process, in a "chain of trust" relationship. + +Secure Boot Process Overview +---------------------------- + +This is a high level overview of the secure boot process. Step by step instructions are supplied under `How To Enable Secure Boot`. Further in-depth details are supplied under `Technical Details`: + +1. The options to enable secure boot are provided in the ``make menuconfig`` hierarchy, under "Secure Boot Configuration". + +2. Secure Boot Configuration includes "Secure boot signing key", which is a file path. This file is a ECDSA public/private key pair in a PEM format file. + +2. The software bootloader image is built by esp-idf with secure boot support enabled and the public key (signature verification) portion of the secure boot signing key compiled in. This software bootloader image is flashed at offset 0x1000. + +3. On first boot, the software bootloader follows the following process to enable secure boot: + - Hardware secure boot support generates a device secure bootloader key (generated via hardware RNG, then stored read/write protected in efuse), and a secure digest. The digest is derived from the key, an IV, and the bootloader image contents. + - The secure digest is flashed at offset 0x0 in the flash. + - Depending on Secure Boot Configuration, efuses are burned to disable JTAG and the ROM BASIC interpreter (it is strongly recommended these options are turned on.) + - Bootloader permanently enables secure boot by burning the ABS_DONE_0 efuse. The software bootloader then becomes protected (the chip will only boot a bootloader image if the digest matches.) + +4. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see `Hardware Secure Boot Support`. + +5. When running in secure boot mode, the software bootloader uses the secure boot signing key (the public key of which is embedded in the bootloader itself, and therefore validated as part of the bootloader) to verify the signature appended to all subsequent partition tables and app images before they are booted. + +Keys +---- + +The following keys are used by the secure boot process: + +- "secure bootloader key" is a 256-bit AES key that is stored in Efuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, the user does not need to supply it (it is optionally possible to supply this key, see `Re-Flashable Software Bootloader`). The Efuse holding this key is read & write protected (preventing software access) before secure boot is enabled. + +- "secure boot signing key" is a standard ECDSA public/private key pair (see `Image Signing Algorithm`) in PEM format. + + - The public key from this key pair (for signature verificaton but not signature creation) is compiled into the software bootloader and used to verify the second stage of booting (partition table, app image) before booting continues. The public key can be freely distributed, it does not need to be kept secret. + + - The private key from this key pair *must be securely kept private*, as anyone who has this key can authenticate to any bootloader that is configured with secure boot and the matching public key. + + +How To Enable Secure Boot +------------------------- + +1. Run ``make menuconfig``, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see `Re-Flashable Software Bootloader`.) + +2. Select a name for the secure boot signing key. This option will appear after secure boot is enabled. The file can be anywhere on your system. A relative path will be evaluated from the project directory. The file does not need to exist yet. + +3. Set other menuconfig options (as desired). Pay particular attention to the "Bootloader Config" options, as you can only flash the bootloader once. Then exit menuconfig and save your configuration + +4. The first time you run ``make``, if the signing key is not found then an error message will be printed with a command to generate a signing key via ``espsecure.py generate_signing_key``. + + **IMPORTANT** A signing key generated this way will use the best random number source available to the OS and its Python installation (`/dev/urandom` on OSX/Linux and `CryptGenRandom()` on Windows). If this random number source is weak, then the private key will be weak. + + **IMPORTANT** For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See `Generating Secure Boot Signing Key` for more details. + +5. Run ``make bootloader`` to build a secure boot enabled bootloader. The output of `make` will include a prompt for a flashing command, using `esptool.py write_flash`. + +6. When you're ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by make) and then wait for flashing to complete. **Remember this is a one time flash, you can't change the bootloader after this!**. + +7. Run `make flash` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4. + + *NOTE*: `make flash` doesn't flash the bootloader if secure boot is enabled. + +8. Reset the ESP32 and it will boot the software bootloader you flashed. The software bootloader will enable secure boot on the chip, and then it verifies the app image signature and boots the app. You should watch the serial console output from the ESP32 to verify that secure boot is enabled and no errors have occured due to the build configuration. + +*NOTE* Secure boot won't be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured. + +9. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed (using the secure bootloader key) and then the software bootloader will verify the signed partition table and app image (using the public key portion of the secure boot signing key). + +Re-Flashable Software Bootloader +-------------------------------- + +Configuration "Secure Boot: One-Time Flash" is the recommended configuration for production devices. In this mode, each device gets a unique key that is never stored outside the device. + +However, an alternative mode "Secure Boot: Reflashable" is also available. This mode allows you to supply a 256-bit key file that is used for the secure bootloader key. As you have the key file, you can generate new bootloader images and secure boot digests for them. + +In the esp-idf build process, this 256-bit key file is derived from the app signing key generated during the generate_signing_key step above. The private key's SHA-256 digest is used as the 256-bit secure bootloader key. This is a convenience so you only need to generate/protect a single private key. + +*NOTE*: Although it's possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The "One-Time Flash" option is recommended for production environments. + +To enable a reflashable bootloader: + +1. In the ``make menuconfig`` step, select "Bootloader Config" -> "Secure Boot" -> "Reflashable". + +2. Follow the steps shown above to choose a signing key file, and generate the key file. + +3. Run ``make bootloader``. A 256-bit key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed - the first set of steps includes an ``espefuse.py burn_key`` command which is used to write the bootloader key to efuse. (Flashing this key is a one-time-only process.) The second set of steps can be used to reflash the bootloader with a pre-calculated digest (generated during the build process). + +4. Resume from `Step 6` of the one-time process, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration. + +Generating Secure Boot Signing Key +---------------------------------- + +The build system will prompt you with a command to generate a new signing key via ``espsecure.py generate_signing_key``. This uses the python-ecdsa library, which in turn uses Python's os.urandom() as a random number source. + +The strength of the signing key is proportional to (a) the random number source of the system, and (b) the correctness of the algorithm used. For production devices, we recommend generating signing keys from a system with a quality entropy source, and using the best available EC key generation utilities. + +For example, to generate a signing key using the openssl command line: + +``` +openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.pem +``` + +Remember that the strength of the secure boot system depends on keeping the signing key private. + +Secure Boot Best Practices +-------------------------- + +* Generate the signing key on a system with a quality source of entropy. +* Keep the signing key private at all times. A leak of this key will compromise the secure boot system. +* Do not allow any third party to observe any aspects of the key generation or signing process using espsecure.py. Both processes are vulnerable to timing or other side-channel attacks. +* Enable all secure boot options in the Secure Boot Configuration. These include flash encryption, disabling of JTAG, disabling BASIC ROM interpeter, and disabling the UART bootloader encrypted flash access. + +Technical Details +----------------- + +The following sections contain low-level descriptions of various technical functions: + +Hardware Secure Boot Support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Secure Boot support hardware can perform three basic operations: + +1. Generate a random sequence of bytes from a hardware random number generator. + +2. Generate a digest from data (usually the bootloader image from flash) using a key stored in Efuse block 2. The key in Efuse can (& should) be read/write protected, which prevents software access. For full details of this algorithm see `Secure Bootloader Digest Algorithm`. The digest can only be read back by software if Efuse ABS_DONE_0 is *not* burned (ie still 0). + +3. Generate a digest from data (usually the bootloader image from flash) using the same algorithm as step 2 and compare it to a pre-calculated digest supplied in a buffer (usually read from flash offset 0x0). The hardware returns a true/false comparison without making the digest available to software. This function is available even when Efuse ABS_DONE_0 is burned. + +Secure Bootloader Digest Algorithm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Starting with an "image" of binary data as input, this algorithm generates a digest as output. The digest is sometimes referred to as an "abstract" in hardware documentation. + +For a Python version of this algorithm, see the `espsecure.py` tool in the components/esptool_py directory. + +Items marked with (^) are to fulfill hardware restrictions, as opposed to cryptographic restrictions. + +1. Prefix the image with a 128 byte randomly generated IV. +2. If the image length is not modulo 128, pad the image to a 128 byte boundary with 0xFF. (^) +3. For each 16 byte plaintext block of the input image: + - Reverse the byte order of the plaintext input block (^) + - Apply AES256 in ECB mode to the plaintext block. + - Reverse the byte order of the ciphertext output block. (^) + - Append to the overall ciphertext output. +4. Byte-swap each 4 byte word of the ciphertext (^) +5. Calculate SHA-512 of the ciphertext. + +Output digest is 192 bytes of data: The 128 byte IV, followed by the 64 byte SHA-512 digest. + +Image Signing Algorithm +~~~~~~~~~~~~~~~~~~~~~~~ + +Deterministic ECDSA as specified by `RFC6979`. + +- Curve is NIST256p (openssl calls this curve "prime256v1", it is also sometimes called secp256r1). +- Hash function is SHA256. +- Key format used for storage is PEM. + - In the bootloader, the public key (for signature verification) is flashed as 64 raw bytes. +- Image signature is 68 bytes - a 4 byte version word (currently zero), followed by a 64 bytes of signature data. These 68 bytes are appended to an app image or partition table data. + + +.. _esp-idf boot process: ../boot-process.rst +.. _RFC6979: https://tools.ietf.org/html/rfc6979 diff --git a/docs/style-guide.rst b/docs/style-guide.rst new file mode 100644 index 0000000000..9bf00f1f7d --- /dev/null +++ b/docs/style-guide.rst @@ -0,0 +1,186 @@ +Espressif IoT Development Framework Style Guide +=============================================== + + +About this guide +---------------- + +Purpose of this style guide is to encourage use of common coding practices within the ESP-IDF. + +Style guide is a set of rules which are aimed to help create readable, maintainable, and robust code. By writing code which looks the same way across the code base we help others read and comprehend the code. By using same conventions for spaces and newlines we reduce chances that future changes will produce huge unreadable diffs. By following common patterns for module structure and by using language features consistently we help others understand code behavior. + +We try to keep rules simple enough, which means that they can not cover all potential cases. In some cases one has to bend these simple rules to achieve readability, maintainability, or robustness. + +When doing modifications to third-party code used in ESP-IDF, follow the way that particular project is written. That will help propose useful changes for merging into upstream project. + +C code formatting +----------------- + +Indentation +^^^^^^^^^^^ + +Use 4 spaces for each indentation level. Don't use tabs for indentation. Configure the editor to emit 4 spaces each time you press tab key. + +Vertical space +^^^^^^^^^^^^^^ + +Place one empty line between functions. Don't begin or end a function with an empty line. +:: + + void function1() + { + do_one_thing(); + do_another_thing(); + // INCORRECT, don't place empty line here + } + // place empty line here + void function2() + { + // INCORRECT, don't use an empty line here + int var = 0; + while (var < SOME_CONSTANT) { + do_stuff(&var); + } + } + +Horizontal space +^^^^^^^^^^^^^^^^ + +Always add single space after conditional and loop keywords:: + + if (condition) { // correct + // ... + } + + switch (n) { // correct + case 0: + // ... + } + + for(int i = 0; i < CONST; ++i) { // INCORRECT + // ... + } + +Add single space around binary operators. No space is necessary for unary operators. It is okay to drop space around multiply and divide operators:: + + const int y = y0 + (x - x0) * (y1 - y0) / (x1 - x0); // correct + + const int y = y0 + (x - x0)*(y1 - y0)/(x1 - x0); // also okay + + int y_cur = -y; // correct + ++y_cur; + + const int y = y0+(x-x0)*(y1-y0)/(x1-x0); // INCORRECT + + +No space is necessary around ``.`` and ``->`` operators. + + +Sometimes adding horizontal space within a line can help make code more readable. For example, you can add space to align function arguments:: + + gpio_matrix_in(PIN_CAM_D6, I2S0I_DATA_IN14_IDX, false); + gpio_matrix_in(PIN_CAM_D7, I2S0I_DATA_IN15_IDX, false); + gpio_matrix_in(PIN_CAM_HREF, I2S0I_H_ENABLE_IDX, false); + gpio_matrix_in(PIN_CAM_PCLK, I2S0I_DATA_IN15_IDX, false); + +Note however that if someone goes to add new line with a longer identifier as first argument (e.g. ``PIN_CAM_VSYNC``), it will not fit. So other lines would have to be realigned, adding meaningless changes to the commit. + +Therefore, use horizontal alignment sparingly, especially if you expect new lines to be added to the list later. + +Never use TAB characters for horizontal alignment. + +Never add trailing whitespace at the end of the line. + + +Braces +^^^^^^ + +- Function definition should have a brace on a separate line:: + + // This is correct: + void function(int arg) + { + + } + + // NOT like this: + void function(int arg) { + + } + +- Within a function, place opening brace on the same line with conditional and loop statements:: + + if (condition) { + do_one(); + } else if (other_condition) { + do_two(); + } + + +Comments +^^^^^^^^ + +Use ``//`` for single line comments. For multi-line comments it is okay to use either ``//`` on each line or a ``/* */`` block. + +Although not directly related to formatting, here are a few notes about using comments effectively. + +- Don't use single comments to disable some functionality:: + + void init_something() + { + setup_dma(); + // load_resources(); // WHY is this thing commented, asks the reader? + start_timer(); + } + +- If some code is no longer required, remove it completely. If you need it you can always look it up in git history of this file. If you disable some call because of temporary reasons, with an intention to restore it in the future, add explanation on the adjacent line:: + + void init_something() + { + setup_dma(); + // TODO: we should load resources here, but loader is not fully integrated yet. + // load_resources(); + start_timer(); + } + +- Same goes for ``#if 0 ... #endif`` blocks. Remove code block completely if it is not used. Otherwise, add comment explaining why the block is disabled. Don't use ``#if 0 ... #endif`` or comments to store code snippets which you may need in the future. + +- Don't add trivial comments about authorship and change date. You can always look up who modified any given line using git. E.g. this comment adds clutter to the code without adding any useful information:: + + void init_something() + { + setup_dma(); + // XXX add 2016-09-01 + init_dma_list(); + fill_dma_item(0); + // end XXX add + start_timer(); + } + + +Formatting your code +^^^^^^^^^^^^^^^^^^^^ + +You can use ``astyle`` program to format your code according to the above recommendations. + +If you are writing a file from scratch, or doing a complete rewrite, feel free to re-format the entire file. If you are changing a small portion of file, don't re-format the code you didn't change. This will help others when they review your changes. + +To re-format a file, run:: + + tools/format.sh components/my_component/file.c + +Documenting code +---------------- + +Please see the guide here: :doc:`documenting-code`. + +Structure and naming +-------------------- + + + +Language features +----------------- + +To be written. + diff --git a/docs/windows-setup.rst b/docs/windows-setup.rst index baea1ac40b..a425f5b3a0 100644 --- a/docs/windows-setup.rst +++ b/docs/windows-setup.rst @@ -1,5 +1,8 @@ -Step 1: Toolchain for Windows: Quick Steps -================================== +Set up of Toolchain for Windows +******************************* + +Step 1: Quick Steps +=================== Windows doesn't have a built-in "make" environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2_ environment to provide. You don't need to use this environment all the time (you can use Eclipse_ or some other front-end), but it runs behind the scenes. diff --git a/examples/01_hello_world/main/component.mk b/examples/01_hello_world/main/component.mk index 24356f23ed..4d3b30caf3 100644 --- a/examples/01_hello_world/main/component.mk +++ b/examples/01_hello_world/main/component.mk @@ -1,10 +1,5 @@ # # Main Makefile. This is basically the same as a component makefile. # -# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, -# this will take the sources in the src/ directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the ESP-IDF documents if you need to do this. -# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) -include $(IDF_PATH)/make/component_common.mk diff --git a/examples/01_hello_world/main/hello_world_main.c b/examples/01_hello_world/main/hello_world_main.c index ad2c0acbbd..1ff190acef 100644 --- a/examples/01_hello_world/main/hello_world_main.c +++ b/examples/01_hello_world/main/hello_world_main.c @@ -27,6 +27,5 @@ void hello_task(void *pvParameter) void app_main() { nvs_flash_init(); - system_init(); xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL); } diff --git a/examples/02_blink/main/blink.c b/examples/02_blink/main/blink.c index 6de0e1fa36..1e49e51b2f 100644 --- a/examples/02_blink/main/blink.c +++ b/examples/02_blink/main/blink.c @@ -43,6 +43,5 @@ void blink_task(void *pvParameter) void app_main() { nvs_flash_init(); - system_init(); xTaskCreate(&blink_task, "blink_task", 512, NULL, 5, NULL); } diff --git a/examples/02_blink/main/component.mk b/examples/02_blink/main/component.mk index 24356f23ed..b4fa72791c 100644 --- a/examples/02_blink/main/component.mk +++ b/examples/02_blink/main/component.mk @@ -1,10 +1,4 @@ # # Main Makefile. This is basically the same as a component makefile. # -# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, -# this will take the sources in the src/ directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the ESP-IDF documents if you need to do this. -# - -include $(IDF_PATH)/make/component_common.mk +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/03_http_request/main/component.mk b/examples/03_http_request/main/component.mk index 24356f23ed..b4fa72791c 100644 --- a/examples/03_http_request/main/component.mk +++ b/examples/03_http_request/main/component.mk @@ -1,10 +1,4 @@ # # Main Makefile. This is basically the same as a component makefile. # -# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, -# this will take the sources in the src/ directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the ESP-IDF documents if you need to do this. -# - -include $(IDF_PATH)/make/component_common.mk +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/03_http_request/main/http_request_main.c b/examples/03_http_request/main/http_request_main.c index 32f75c0da2..2c203f8394 100644 --- a/examples/03_http_request/main/http_request_main.c +++ b/examples/03_http_request/main/http_request_main.c @@ -175,7 +175,6 @@ static void http_get_task(void *pvParameters) void app_main() { nvs_flash_init(); - system_init(); initialise_wifi(); xTaskCreate(&http_get_task, "http_get_task", 2048, NULL, 5, NULL); } diff --git a/examples/04_https_request/main/cert.c b/examples/04_https_request/main/cert.c deleted file mode 100644 index 7acc438ef3..0000000000 --- a/examples/04_https_request/main/cert.c +++ /dev/null @@ -1,44 +0,0 @@ -/* This is the CA certificate for the CA trust chain of - www.howsmyssl.com in PEM format, as dumped via: - - openssl s_client -showcerts -connect www.howsmyssl.com:443 -#include -#include - -/* - 1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3 - i:/O=Digital Signature Trust Co./CN=DST Root CA X3 - */ -const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n" -"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\r\n" -"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\r\n" -"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\r\n" -"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\r\n" -"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\r\n" -"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\r\n" -"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\r\n" -"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\r\n" -"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\r\n" -"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\r\n" -"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\r\n" -"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\r\n" -"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\r\n" -"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\r\n" -"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\r\n" -"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\r\n" -"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\r\n" -"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\r\n" -"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\r\n" -"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\r\n" -"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\r\n" -"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\r\n" -"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\r\n" -"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\r\n" -"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\r\n" -"-----END CERTIFICATE-----\r\n"; - - diff --git a/examples/04_https_request/main/component.mk b/examples/04_https_request/main/component.mk index 24356f23ed..f4502c25db 100644 --- a/examples/04_https_request/main/component.mk +++ b/examples/04_https_request/main/component.mk @@ -1,10 +1,10 @@ # # Main Makefile. This is basically the same as a component makefile. # -# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, -# this will take the sources in the src/ directory, compile them and link them into -# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, -# please read the ESP-IDF documents if you need to do this. -# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + +# embed files from the "certs" directory as binary data symbols +# in the app +COMPONENT_EMBED_TXTFILES := server_root_cert.pem + -include $(IDF_PATH)/make/component_common.mk diff --git a/examples/04_https_request/main/https_request_main.c b/examples/04_https_request/main/https_request_main.c index 0c8b2463f8..2ad56681d0 100644 --- a/examples/04_https_request/main/https_request_main.c +++ b/examples/04_https_request/main/https_request_main.c @@ -74,8 +74,18 @@ static const char *REQUEST = "GET " WEB_URL " HTTP/1.1\n" "User-Agent: esp-idf/1.0 esp32\n" "\n"; -/* Root cert for howsmyssl.com, found in cert.c */ -extern const char *server_root_cert; +/* Root cert for howsmyssl.com, taken from server_root_cert.pem + + The PEM file was extracted from the output of this command: + openssl s_client -showcerts -connect www.howsmyssl.com:443 +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "esp_deepsleep.h" +#include "nvs_flash.h" + +#include "lwip/err.h" +#include "apps/sntp/sntp.h" + +/* The examples use simple WiFi configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" +*/ +#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID +#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD + +/* FreeRTOS event group to signal when we are connected & ready to make a request */ +static EventGroupHandle_t wifi_event_group; + +/* The event group allows multiple bits for each event, + but we only care about one event - are we connected + to the AP with an IP? */ +const int CONNECTED_BIT = BIT0; + +static const char *TAG = "example"; + +/* Variable holding number of times ESP32 restarted since first boot. + * It is placed into RTC memory using RTC_DATA_ATTR and + * maintains its value when ESP32 wakes from deep sleep. + */ +RTC_DATA_ATTR static int boot_count = 0; + +static void obtain_time(void); +static void initialize_sntp(void); +static void initialise_wifi(void); +static esp_err_t event_handler(void *ctx, system_event_t *event); + + +void app_main() +{ + ++boot_count; + ESP_LOGI(TAG, "Boot count: %d", boot_count); + + time_t now; + struct tm timeinfo; + time(&now); + localtime_r(&now, &timeinfo); + // Is time set? If not, tm_year will be (1970 - 1900). + if (timeinfo.tm_year < (2016 - 1900)) { + ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP."); + obtain_time(); + // update 'now' variable with current time + time(&now); + } + char strftime_buf[64]; + + // Set timezone to Eastern Standard Time and print local time + setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1); + tzset(); + localtime_r(&now, &timeinfo); + strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); + ESP_LOGI(TAG, "The current date/time in New York is: %s", strftime_buf); + + // Set timezone to China Standard Time + setenv("TZ", "CST-8CDT-9,M4.2.0/2,M9.2.0/3", 1); + tzset(); + localtime_r(&now, &timeinfo); + strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); + ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf); + + const int deep_sleep_sec = 10; + ESP_LOGI(TAG, "Entering deep sleep for %d seconds", deep_sleep_sec); + system_deep_sleep(1000000LL * deep_sleep_sec); +} + +static void obtain_time(void) +{ + nvs_flash_init(); + initialise_wifi(); + xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, + false, true, portMAX_DELAY); + initialize_sntp(); + + // wait for time to be set + time_t now = 0; + struct tm timeinfo = { 0 }; + int retry = 0; + const int retry_count = 10; + while(timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count) { + ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); + vTaskDelay(2000 / portTICK_PERIOD_MS); + time(&now); + localtime_r(&now, &timeinfo); + } +} + +static void initialize_sntp(void) +{ + ESP_LOGI(TAG, "Initializing SNTP"); + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, "pool.ntp.org"); + sntp_init(); +} + +static void initialise_wifi(void) +{ + tcpip_adapter_init(); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) ); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); + ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_WIFI_SSID, + .password = EXAMPLE_WIFI_PASS, + }, + }; + ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid); + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_ERROR_CHECK( esp_wifi_start() ); +} + +static esp_err_t event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + /* This is a workaround as ESP32 WiFi libs don't currently + auto-reassociate. */ + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} diff --git a/examples/07_nvs_rw_value/Makefile b/examples/07_nvs_rw_value/Makefile new file mode 100644 index 0000000000..fdfc09c574 --- /dev/null +++ b/examples/07_nvs_rw_value/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := nvs-rw-value + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/07_nvs_rw_value/README.md b/examples/07_nvs_rw_value/README.md new file mode 100644 index 0000000000..09cd364e8d --- /dev/null +++ b/examples/07_nvs_rw_value/README.md @@ -0,0 +1,13 @@ +# Non-Volatile Storage (NVS) Read and Write Example + +Demonstrates how to read and write a single integer value using NVS. + +The value holds the number of ESP32 module restarts. Since it is written to NVS, the value is preserved between restarts. + +Example also shows how to check if read / write operation was successful, or certain value is not initialized in NVS. Diagnostic is provided in plain text to help track program flow and capture any issues on the way. + +Check another example *08_nvs_rw_blob*, that shows how to read and write variable length binary data (blob). + +Detailed functional description of NVS and API is provided in [documentation](http://esp-idf.readthedocs.io/en/latest/api/nvs_flash.html). + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/07_nvs_rw_value/main/component.mk b/examples/07_nvs_rw_value/main/component.mk new file mode 100644 index 0000000000..d33485c26c --- /dev/null +++ b/examples/07_nvs_rw_value/main/component.mk @@ -0,0 +1,2 @@ + +include $(IDF_PATH)/make/component_common.mk diff --git a/examples/07_nvs_rw_value/main/nvs_rw_value.c b/examples/07_nvs_rw_value/main/nvs_rw_value.c new file mode 100644 index 0000000000..978c48edb8 --- /dev/null +++ b/examples/07_nvs_rw_value/main/nvs_rw_value.c @@ -0,0 +1,80 @@ +/* Non-Volatile Storage (NVS) Read and Write a Value - Example + + For other examples please check: + https://github.com/espressif/esp-idf/tree/master/examples + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "nvs.h" + +void app_main() +{ + nvs_flash_init(); + + nvs_handle my_handle; + esp_err_t err; + + printf("\n"); + + // Open + printf("Opening Non-Volatile Storage (NVS) ... "); + err = nvs_open("storage", NVS_READWRITE, &my_handle); + if (err != ESP_OK) { + printf("Error (%d) opening NVS!\n", err); + } else { + printf("Done\n"); + + // Read + printf("Reading restart counter from NVS ... "); + int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS + err = nvs_get_i32(my_handle, "restart_conter", &restart_counter); + switch (err) { + case ESP_OK: + printf("Done\n"); + printf("Restart counter = %d\n", restart_counter); + break; + case ESP_ERR_NVS_NOT_FOUND: + printf("The value is not initialized yet!\n"); + break; + default : + printf("Error (%d) reading!\n", err); + } + + // Write + printf("Updating restart counter in NVS ... "); + restart_counter++; + err = nvs_set_i32(my_handle, "restart_conter", restart_counter); + printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); + + // Commit written value. + // After setting any values, nvs_commit() must be called to ensure changes are written + // to flash storage. Implementations may write to storage at other times, + // but this is not guaranteed. + printf("Committing updates in NVS ... "); + err = nvs_commit(my_handle); + printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); + + // Close + nvs_close(my_handle); + } + + printf("\n"); + + // Restart module + for (int i = 10; i >= 0; i--) { + printf("Restarting in %d seconds...\n", i); + vTaskDelay(1000 / portTICK_RATE_MS); + } + printf("Restarting now.\n"); + fflush(stdout); + system_restart(); +} diff --git a/examples/08_nvs_rw_blob/Makefile b/examples/08_nvs_rw_blob/Makefile new file mode 100644 index 0000000000..717744bbe8 --- /dev/null +++ b/examples/08_nvs_rw_blob/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := nvs-rw-blob + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/08_nvs_rw_blob/README.md b/examples/08_nvs_rw_blob/README.md new file mode 100644 index 0000000000..81a0e36c71 --- /dev/null +++ b/examples/08_nvs_rw_blob/README.md @@ -0,0 +1,14 @@ +# Non-Volatile Storage (NVS) Read and Write Example + +Demonstrates how to read and write a single integer value and a blob (binary large object) using NVS to preserve them between ESP32 module restarts. + + * value - tracks number of ESP32 module soft and hard restarts. + * blob - contains a table with module run times. The table is read from NVS to dynamically allocated RAM. New run time is added to the table on each manually triggered soft restart and written back to NVS. Triggering is done by pulling down GPIO0. + +Example also shows how to implement diagnostics if read / write operation was successful. + +If not done already, consider checking simpler example *07_nvs_rw_value*, that has been used as a starting point for preparing this one. + +Detailed functional description of NVS and API is provided in [documentation](http://esp-idf.readthedocs.io/en/latest/api/nvs_flash.html). + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/08_nvs_rw_blob/main/component.mk b/examples/08_nvs_rw_blob/main/component.mk new file mode 100644 index 0000000000..d33485c26c --- /dev/null +++ b/examples/08_nvs_rw_blob/main/component.mk @@ -0,0 +1,2 @@ + +include $(IDF_PATH)/make/component_common.mk diff --git a/examples/08_nvs_rw_blob/main/nvs_rw_blob.c b/examples/08_nvs_rw_blob/main/nvs_rw_blob.c new file mode 100644 index 0000000000..3fbdfcacd6 --- /dev/null +++ b/examples/08_nvs_rw_blob/main/nvs_rw_blob.c @@ -0,0 +1,178 @@ +/* Non-Volatile Storage (NVS) Read and Write a Blob - Example + + For other examples please check: + https://github.com/espressif/esp-idf/tree/master/examples + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "nvs.h" +#include "driver/gpio.h" + +#define STORAGE_NAMESPACE "storage" + +/* Save the number of module restarts in NVS + by first reading and then incrementing + the number that has been saved previously. + Return an error if anything goes wrong + during this process. + */ +esp_err_t save_restart_counter(void) +{ + nvs_handle my_handle; + esp_err_t err; + + // Open + err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle); + if (err != ESP_OK) return err; + + // Read + int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS + err = nvs_get_i32(my_handle, "restart_conter", &restart_counter); + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err; + + // Write + restart_counter++; + err = nvs_set_i32(my_handle, "restart_conter", restart_counter); + if (err != ESP_OK) return err; + + // Commit written value. + // After setting any values, nvs_commit() must be called to ensure changes are written + // to flash storage. Implementations may write to storage at other times, + // but this is not guaranteed. + err = nvs_commit(my_handle); + if (err != ESP_OK) return err; + + // Close + nvs_close(my_handle); + return ESP_OK; +} + +/* Save new run time value in NVS + by first reading a table of previously saved values + and then adding the new value at the end of the table. + Return an error if anything goes wrong + during this process. + */ +esp_err_t save_run_time(void) +{ + nvs_handle my_handle; + esp_err_t err; + + // Open + err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle); + if (err != ESP_OK) return err; + + // Read the size of memory space required for blob + size_t required_size = 0; // value will default to 0, if not set yet in NVS + err = nvs_get_blob(my_handle, "run_time", NULL, &required_size); + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err; + + // Read previously saved blob if available + uint32_t* run_time = malloc(required_size + sizeof(uint32_t)); + if (required_size > 0) { + err = nvs_get_blob(my_handle, "run_time", run_time, &required_size); + if (err != ESP_OK) return err; + } + + // Write value including previously saved blob if available + required_size += sizeof(uint32_t); + run_time[required_size / sizeof(uint32_t) - 1] = xTaskGetTickCount() * portTICK_PERIOD_MS; + err = nvs_set_blob(my_handle, "run_time", run_time, required_size); + if (err != ESP_OK) return err; + + free(run_time); + + // Commit + err = nvs_commit(my_handle); + if (err != ESP_OK) return err; + + // Close + nvs_close(my_handle); + return ESP_OK; +} + +/* Read from NVS and print restart counter + and the table with run times. + Return an error if anything goes wrong + during this process. + */ +esp_err_t print_what_saved(void) +{ + nvs_handle my_handle; + esp_err_t err; + + // Open + err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle); + if (err != ESP_OK) return err; + + // Read restart counter + int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS + err = nvs_get_i32(my_handle, "restart_conter", &restart_counter); + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err; + printf("Restart counter = %d\n", restart_counter); + + // Read run time blob + size_t required_size = 0; // value will default to 0, if not set yet in NVS + // obtain required memory space to store blob being read from NVS + err = nvs_get_blob(my_handle, "run_time", NULL, &required_size); + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err; + printf("Run time:\n"); + if (required_size == 0) { + printf("Nothing saved yet!\n"); + } else { + uint32_t* run_time = malloc(required_size); + err = nvs_get_blob(my_handle, "run_time", run_time, &required_size); + if (err != ESP_OK) return err; + for (int i = 0; i < required_size / sizeof(uint32_t); i++) { + printf("%d: %d\n", i + 1, run_time[i]); + } + free(run_time); + } + + // Close + nvs_close(my_handle); + return ESP_OK; +} + + +void app_main() +{ + nvs_flash_init(); + + esp_err_t err; + + err = print_what_saved(); + if (err != ESP_OK) printf("Error (%d) reading data from NVS!\n", err); + + err = save_restart_counter(); + if (err != ESP_OK) printf("Error (%d) saving restart counter to NVS!\n", err); + + gpio_pad_select_gpio(GPIO_NUM_0); + gpio_set_direction(GPIO_NUM_0, GPIO_MODE_DEF_INPUT); + + /* Read the status of GPIO0. If GPIO0 is LOW for longer than 1000 ms, + then save module's run time and restart it + */ + while (1) { + if (gpio_get_level(GPIO_NUM_0) == 0) { + vTaskDelay(1000 / portTICK_RATE_MS); + if(gpio_get_level(GPIO_NUM_0) == 0) { + err = save_run_time(); + if (err != ESP_OK) printf("Error (%d) saving run time blob to NVS!\n", err); + printf("Restarting...\n"); + fflush(stdout); + system_restart(); + } + } + vTaskDelay(200 / portTICK_RATE_MS); + } +} diff --git a/examples/README.md b/examples/README.md index 2cf66b9d07..e4422e91bf 100644 --- a/examples/README.md +++ b/examples/README.md @@ -26,7 +26,7 @@ If you're looking for a more bare-bones project to start from, try [esp-idf-temp If you have a new example you think we'd like, please consider sending it to us as a Pull Request. -Please read the esp-idf CONTRIBUTING.md file which lays out general contribution rules. +Please read the esp-idf CONTRIBUTING.rst file which lays out general contribution rules. In addition, here are some tips for creating good examples: diff --git a/make/build_examples.sh b/make/build_examples.sh index d264862874..a522666a98 100755 --- a/make/build_examples.sh +++ b/make/build_examples.sh @@ -15,16 +15,15 @@ RESULT=0 set -e for example in ${IDF_PATH}/examples/*; do - [ -f ${example}/Makefile ] || continue - echo "Building ${example} as ${EXAMPLE_NUM}..." - mkdir ${EXAMPLE_NUM} - cp -r ${example} ${EXAMPLE_NUM} - pushd ${EXAMPLE_NUM}/`basename ${example}` - # can't do "make defconfig all" as this will trip menuconfig - # sometimes - make defconfig && make || RESULT=$? - popd - EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 )) + [ -f ${example}/Makefile ] || continue + echo "Building ${example} as ${EXAMPLE_NUM}..." + mkdir ${EXAMPLE_NUM} + cp -r ${example} ${EXAMPLE_NUM} + pushd ${EXAMPLE_NUM}/`basename ${example}` + # build non-verbose first, only build verbose if there's an error + make defconfig all || (RESULT=$?; make V=1) + popd + EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 )) done exit $RESULT diff --git a/make/common.mk b/make/common.mk index 14aa4074b3..6e4fa75ab5 100644 --- a/make/common.mk +++ b/make/common.mk @@ -1,12 +1,14 @@ -# Functionality common to both top-level project makefile -# and component makefiles +# Functionality common to both top-level project makefile (project.mk) +# and component makefiles (component_wrapper.mk) # -# Include project config file, if it exists. +# Include project config makefile, if it exists. # -# (Note that we only rebuild auto.conf automatically for some targets, -# see project_config.mk for details.) --include $(PROJECT_PATH)/build/include/config/auto.conf +# (Note that we only rebuild this makefile automatically for some +# targets, see project_config.mk for details.) +SDKCONFIG_MAKEFILE ?= $(abspath $(BUILD_DIR_BASE)/include/config/auto.conf) +-include $(SDKCONFIG_MAKEFILE) +export SDKCONFIG_MAKEFILE # sub-makes (like bootloader) will reuse this path #Handling of V=1/VERBOSE=1 flag # @@ -14,13 +16,14 @@ # if V is unset or not 1, $(summary) echoes a summary and $(details) does nothing V ?= $(VERBOSE) ifeq ("$(V)","1") -Q := summary := @true details := @echo else -Q := @ summary := @echo details := @true + +# disable echoing of commands, directory names +MAKEFLAGS += --silent endif # Pseudo-target to check a git submodule has been properly initialised @@ -34,8 +37,8 @@ endif define SubmoduleCheck $(1): @echo "WARNING: Missing submodule $(2) for $$@..." - $(Q) [ -d ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) - $(Q) [ -x $(which git) ] || ( echo "ERROR: Need to run 'git submodule --init' in esp-idf root directory."; exit 1) + [ -d ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) + [ -x $(which git) ] || ( echo "ERROR: Need to run 'git submodule --init' in esp-idf root directory."; exit 1) @echo "Attempting 'git submodule update --init' in esp-idf root directory..." cd ${IDF_PATH} && git submodule update --init $(2) @@ -53,8 +56,26 @@ endef # convenience variable for printing an 80 asterisk wide separator line SEPARATOR:="*******************************************************************************" -# macro to remove quotes from an argument, ie $(call dequote (CONFIG_BLAH)) +# macro to remove quotes from an argument, ie $(call dequote,$(CONFIG_BLAH)) define dequote $(subst ",,$(1)) endef # " comment kept here to keep syntax highlighting happy + + +# macro to keep an absolute path as-is, but resolve a relative path +# against a particular parent directory +# +# $(1) path to resolve +# $(2) directory to resolve non-absolute path against +# +# Path and directory don't have to exist (definition of a "relative +# path" is one that doesn't start with /) +# +# $(2) can contain a trailing forward slash or not, result will not +# double any path slashes. +# +# example $(call resolvepath,$(CONFIG_PATH),$(CONFIG_DIR)) +define resolvepath +$(if $(filter /%,$(1)),$(1),$(subst //,/,$(2)/$(1))) +endef diff --git a/make/component_common.mk b/make/component_common.mk index ebad525a76..187e1ed63a 100644 --- a/make/component_common.mk +++ b/make/component_common.mk @@ -1,110 +1 @@ -# Component common makefile -# -# This Makefile gets included in the Makefile of all the components to set the correct include paths etc. -# PWD is the build directory of the component and the top Makefile is the one in the -# component source dir. -# -# The way the Makefile differentiates between those two is by looking at the environment -# variable PROJECT_PATH. If this is set (to the basepath of the project), we're building a -# component and its Makefile has included this makefile. If not, we're building the entire project. -# - -# -# This Makefile requires the environment variable IDF_PATH to be set -# to the top-level directory where ESP-IDF is located (the directory -# containing this 'make' directory). -# - -ifeq ("$(PROJECT_PATH)","") -$(error Make was invoked from $(CURDIR). However please do not run make from the sdk or a component directory; invoke make from the project directory. See the ESP-IDF README for details.) -endif - -# Find the path to the component -COMPONENT_PATH := $(abspath $(dir $(firstword $(MAKEFILE_LIST)))) -export COMPONENT_PATH - -include $(IDF_PATH)/make/common.mk - -#Some of these options are overridable by the component's component.mk Makefile - -#Name of the component -COMPONENT_NAME ?= $(lastword $(subst /, ,$(realpath $(COMPONENT_PATH)))) - -#Absolute path of the .a file -COMPONENT_LIBRARY := lib$(COMPONENT_NAME).a - -#Source dirs a component has. Default to root directory of component. -COMPONENT_SRCDIRS ?= . - -#Object files which need to be linked into the library -#By default we take all .c/.S files in the component directory. -ifeq ("$(COMPONENT_OBJS)", "") -#Find all source files in all COMPONENT_SRCDIRS -COMPONENT_OBJS := $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.c,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.c))) -COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cpp,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.cpp))) -COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.S,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.S))) -#Make relative by removing COMPONENT_PATH from all found object paths -COMPONENT_OBJS := $(patsubst $(COMPONENT_PATH)/%,%,$(COMPONENT_OBJS)) -endif - -#By default, include only the include/ dir. -COMPONENT_ADD_INCLUDEDIRS ?= include -COMPONENT_ADD_LDFLAGS ?= -l$(COMPONENT_NAME) - -#If we're called to compile something, we'll get passed the COMPONENT_INCLUDES -#variable with all the include dirs from all the components in random order. This -#means we can accidentally grab a header from another component before grabbing our own. -#To make sure that does not happen, re-order the includes so ours come first. -OWN_INCLUDES:=$(abspath $(addprefix $(COMPONENT_PATH)/,$(COMPONENT_ADD_INCLUDEDIRS) $(COMPONENT_PRIV_INCLUDEDIRS))) -COMPONENT_INCLUDES := $(OWN_INCLUDES) $(filter-out $(OWN_INCLUDES),$(COMPONENT_INCLUDES)) - -#This target is used to collect variable values from inside project.mk -# see project.mk GetVariable macro for details. -get_variable: - @echo "$(GET_VARIABLE)=$(call $(GET_VARIABLE)) " - -#Targets for build/clean. Use builtin recipe if component Makefile -#hasn't defined its own. -ifeq ("$(COMPONENT_OWNBUILDTARGET)", "") -build: $(COMPONENT_LIBRARY) - @mkdir -p $(COMPONENT_SRCDIRS) - -#Build the archive. We remove the archive first, otherwise ar will get confused if we update -#an archive when multiple filenames have the same name (src1/test.o and src2/test.o) -$(COMPONENT_LIBRARY): $(COMPONENT_OBJS) - $(summary) AR $@ - $(Q) rm -f $@ - $(Q) $(AR) cru $@ $(COMPONENT_OBJS) -endif - -ifeq ("$(COMPONENT_OWNCLEANTARGET)", "") -clean: - $(summary) RM $(COMPONENT_LIBRARY) $(COMPONENT_OBJS) $(COMPONENT_OBJS:.o=.d) $(COMPONENT_EXTRA_CLEAN) - $(Q) rm -f $(COMPONENT_LIBRARY) $(COMPONENT_OBJS) $(COMPONENT_OBJS:.o=.d) $(COMPONENT_EXTRA_CLEAN) -endif - -#Include all dependency files already generated --include $(COMPONENT_OBJS:.o=.d) - -#This pattern is generated for each COMPONENT_SRCDIR to compile the files in it. -define GenerateCompileTargets -# $(1) - directory containing source files, relative to $(COMPONENT_PATH) -$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.c | $(1) - $$(summary) CC $$@ - $$(Q) $$(CC) $$(CFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ - -$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cpp | $(1) - $$(summary) CC $$@ - $$(Q) $$(CXX) $$(CXXFLAGS) $$(addprefix -I,$$(COMPONENT_INCLUDES)) $$(addprefix -I,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ - -$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.S | $(1) - $$(summary) CC $$@ - $$(Q) $$(CC) $$(CFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ - -# CWD is build dir, create the build subdirectory if it doesn't exist -$(1): - @mkdir -p $(1) -endef - -#Generate all the compile target recipes -$(foreach srcdir,$(COMPONENT_SRCDIRS), $(eval $(call GenerateCompileTargets,$(srcdir)))) +$(warning Deprecated feature: No longer necessary to include component_common.mk from $(COMPONENT_PATH)/component.mk) diff --git a/make/component_wrapper.mk b/make/component_wrapper.mk new file mode 100644 index 0000000000..55a135158a --- /dev/null +++ b/make/component_wrapper.mk @@ -0,0 +1,209 @@ +# Component wrapper makefile +# +# This makefile gets called recursively from the project make, once for each component. +# COMPONENT_MAKEFILE is set to point at the component.mk file for the component itself, +# which is included as part of this process (after default variables are defined). +# +# This makefile comprises multiple stages, marked in blocked comments below. +# +# CWD is the build directory of the component. + +ifndef PROJECT_PATH +$(error Make was invoked from $(CURDIR). However please do not run make from the sdk or a component directory; invoke make from the project directory. See the ESP-IDF README for details.) +endif + + +################################################################################ +# 1) Set default variables for the component build (including configuration +# loaded from sdkconfig.) +################################################################################ + +# Find the path to the component +COMPONENT_PATH := $(abspath $(dir $(COMPONENT_MAKEFILE))) +export COMPONENT_PATH + +# COMPONENT_BUILD_DIR is otherwise known as CWD for the build +COMPONENT_BUILD_DIR := $(abspath .) + +# include elements common to both project & component makefiles +# (includes project configuration set via menuconfig) +include $(IDF_PATH)/make/common.mk + +# Some of the following defaults may be overriden by the component's component.mk makefile, +# during the next step: + +# Name of the component +COMPONENT_NAME := $(lastword $(subst /, ,$(realpath $(COMPONENT_PATH)))) + +# Absolute path of the .a file +COMPONENT_LIBRARY = lib$(COMPONENT_NAME).a + +# Source dirs a component has. Default to root directory of component. +COMPONENT_SRCDIRS = . + +#Names of binary & text files to embed as raw content in the component library +COMPONENT_EMBED_FILES ?= +COMPONENT_EMBED_TXTFILES ?= + +# By default, include only the include/ dir. +COMPONENT_ADD_INCLUDEDIRS = include +COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) + + +################################################################################ +# 2) Include the component.mk for the specific component (COMPONENT_MAKEFILE) to +# override variables & optionally define custom targets. +################################################################################ + +include $(COMPONENT_MAKEFILE) + + +################################################################################ +# 3) Set variables that depend on values that may changed by component.mk +################################################################################ + +# Object files which need to be linked into the library +# By default we take all .c, .cpp & .S files in COMPONENT_SRCDIRS. +ifndef COMPONENT_OBJS +# Find all source files in all COMPONENT_SRCDIRS +COMPONENT_OBJS := $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.c,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.c))) +COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cpp,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.cpp))) +COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.S,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.S))) +# Make relative by removing COMPONENT_PATH from all found object paths +COMPONENT_OBJS := $(patsubst $(COMPONENT_PATH)/%,%,$(COMPONENT_OBJS)) +endif + +# Object files with embedded binaries to add to the component library +# Correspond to the files named in COMPONENT_EMBED_FILES & COMPONENT_EMBED_TXTFILES +COMPONENT_EMBED_OBJS ?= $(addsuffix .bin.o,$(COMPONENT_EMBED_FILES)) $(addsuffix .txt.o,$(COMPONENT_EMBED_TXTFILES)) + + +# If we're called to compile something, we'll get passed the COMPONENT_INCLUDES +# variable with all the include dirs from all the components in random order. This +# means we can accidentally grab a header from another component before grabbing our own. +# To make sure that does not happen, re-order the includes so ours come first. +OWN_INCLUDES:=$(abspath $(addprefix $(COMPONENT_PATH)/,$(COMPONENT_ADD_INCLUDEDIRS) $(COMPONENT_PRIV_INCLUDEDIRS))) +COMPONENT_INCLUDES := $(OWN_INCLUDES) $(filter-out $(OWN_INCLUDES),$(COMPONENT_INCLUDES)) + + +################################################################################ +# 4) Define a target to generate component_project_vars.mk Makefile which +# contains common per-component settings which are included directly in the +# top-level project make +################################################################################ + +# macro to generate variable-relative paths inside component_project_vars.mk, whenever possible +# ie put literal $(IDF_PATH), $(PROJECT_PATH) and $(BUILD_DIR_BASE) into the generated +# makefiles where possible. +# +# This means if directories move (breaking absolute paths), don't need to 'make clean' +define MakeVariablePath +$(subst $(IDF_PATH),$$(IDF_PATH),$(subst $(PROJECT_PATH),$$(PROJECT_PATH),$(subst $(BUILD_DIR_BASE),\$$(BUILD_DIR_BASE),$(1)))) +endef + +# component_project_vars.mk target for the component. This is used to +# take component.mk variables COMPONENT_ADD_INCLUDEDIRS, +# COMPONENT_ADD_LDFLAGS and COMPONENT_DEPENDS and inject those into +# the project make pass. +# +# The target here has no dependencies, as the parent target in +# project.mk evaluates dependencies before calling down to here. See +# GenerateComponentTargets macro in project.mk. +# +# If you are thinking of editing the output of this target for a +# component-specific feature, please don't! What you want is a +# Makefile.projbuild for your component (see docs/build-system.rst for +# more.) +component_project_vars.mk:: + $(details) "Building component project variables list $(abspath $@)" + @echo '# Automatically generated build file. Do not edit.' > $@ + @echo 'COMPONENT_INCLUDES += $(call MakeVariablePath,$(addprefix $(COMPONENT_PATH)/,$(COMPONENT_ADD_INCLUDEDIRS)))' >> $@ + @echo 'COMPONENT_LDFLAGS += $(call MakeVariablePath,$(COMPONENT_ADD_LDFLAGS))' >> $@ + @echo '$(COMPONENT_NAME)-build: $(addsuffix -build,$(COMPONENT_DEPENDS))' >> $@ + + +################################################################################ +# 5) If COMPONENT_OWNBUILDTARGET / COMPONENT_OWNCLEANTARGET is not set by component.mk, +# define default build, clean, etc. targets +################################################################################ + +# If COMPONENT_OWNBUILDTARGET is not set, define a phony build target and +# a COMPONENT_LIBRARY link target. +ifndef COMPONENT_OWNBUILDTARGET +.PHONY: build +build: $(COMPONENT_LIBRARY) + @mkdir -p $(COMPONENT_SRCDIRS) + +# Build the archive. We remove the archive first, otherwise ar will get confused if we update +# an archive when multiple filenames have the same name (src1/test.o and src2/test.o) +$(COMPONENT_LIBRARY): $(COMPONENT_OBJS) $(COMPONENT_EMBED_OBJS) + $(summary) AR $@ + rm -f $@ + $(AR) cru $@ $^ +endif + +# If COMPONENT_OWNCLEANTARGET is not set, define a phony clean target +ifndef COMPONENT_OWNCLEANTARGET +CLEAN_FILES = $(COMPONENT_LIBRARY) $(COMPONENT_OBJS) $(COMPONENT_OBJS:.o=.d) $(COMPONENT_EMBED_OBJS) $(COMPONENT_EXTRA_CLEAN) component_project_vars.mk +.PHONY: clean +clean: + $(summary) RM $(CLEAN_FILES) + rm -f $(CLEAN_FILES) +endif + +# Include all dependency files already generated +-include $(COMPONENT_OBJS:.o=.d) + +# This pattern is generated for each COMPONENT_SRCDIR to compile the files in it. +define GenerateCompileTargets +# $(1) - directory containing source files, relative to $(COMPONENT_PATH) +$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.c | $(1) + $$(summary) CC $$@ + $$(CC) $$(CFLAGS) $$(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ + +$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cpp | $(1) + $$(summary) CXX $$@ + $$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(addprefix -I,$$(COMPONENT_INCLUDES)) $$(addprefix -I,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ + +$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.S | $(1) + $$(summary) AS $$@ + $$(CC) $$(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ + +# CWD is build dir, create the build subdirectory if it doesn't exist +$(1): + @mkdir -p $(1) +endef + +# Generate all the compile target patterns +$(foreach srcdir,$(COMPONENT_SRCDIRS), $(eval $(call GenerateCompileTargets,$(srcdir)))) + +## Support for embedding binary files into the ELF as symbols + +OBJCOPY_EMBED_ARGS := --input binary --output elf32-xtensa-le --binary-architecture xtensa --rename-section .data=.rodata.embedded + +# Generate pattern for embedding text or binary files into the app +# $(1) is name of file (as relative path inside component) +# $(2) is txt or bin depending on file contents +# +# txt files are null-terminated before being embedded (otherwise +# identical behaviour.) +# +# Files are temporarily copied to the build directory before objcopy, +# because objcopy generates the symbol name from the full command line +# path to the input file. +define GenerateEmbedTarget +$(1).$(2).o: $(call resolvepath,$(1),$(COMPONENT_PATH)) | $$(dir $(1)) + $(summary) EMBED $$@ + $$(if $$(filter-out $$(notdir $$(abspath $$<)),$$(abspath $$(notdir $$<))), cp $$< $$(notdir $$<) ) # copy input file to build dir, unless already in build dir + $$(if $$(subst bin,,$(2)),echo -ne '\0' >> $$(notdir $$<) ) # trailing NUL byte on text output + $(OBJCOPY) $(OBJCOPY_EMBED_ARGS) $$(notdir $$<) $$@ + rm $$(notdir $$<) +endef + +# generate targets to embed binary & text files +$(foreach binfile,$(COMPONENT_EMBED_FILES), $(eval $(call GenerateEmbedTarget,$(binfile),bin))) + +$(foreach txtfile,$(COMPONENT_EMBED_TXTFILES), $(eval $(call GenerateEmbedTarget,$(txtfile),txt))) + +# generate targets to create binary embed directories +$(foreach bindir,$(sort $(dir $(COMPONENT_EMBED_FILES))), $(eval $(call GenerateBuildDirTarget,$(bindir)))) diff --git a/make/project.mk b/make/project.mk index d91165cfd7..08c7dd89a9 100644 --- a/make/project.mk +++ b/make/project.mk @@ -11,13 +11,13 @@ # .PHONY: build-components menuconfig defconfig all build clean all_binaries -all: all_binaries # other components will add dependencies to 'all_binaries' - @echo "To flash all build output, run 'make flash' or:" - @echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) - -# (the reason all_binaries is used instead of 'all' is so that the flash target -# can build everything without triggering the per-component "to flash..." -# output targets.) +all: all_binaries +# see below for recipe of 'all' target +# +# # other components will add dependencies to 'all_binaries'. The +# reason all_binaries is used instead of 'all' is so that the flash +# target can build everything without triggering the per-component "to +# flash..." output targets.) help: @echo "Welcome to Espressif IDF build system. Some useful make targets:" @@ -36,102 +36,101 @@ help: @echo "See also 'make bootloader', 'make bootloader-flash', 'make bootloader-clean', " @echo "'make partition_table', etc, etc." +# dependency checks +ifndef MAKE_RESTARTS +ifeq ("$(filter 4.% 3.81 3.82,$(MAKE_VERSION))","") +$(warning "esp-idf build system only supports GNU Make versions 3.81 or newer. You may see unexpected results with other Makes.") +endif +endif + # disable built-in make rules, makes debugging saner +MAKEFLAGS_OLD := $(MAKEFLAGS) MAKEFLAGS +=-rR -# Figure out PROJECT_PATH if not set -ifeq ("$(PROJECT_PATH)","") -#The path to the project: we assume the Makefile including this file resides -#in the root of that directory. +# Default path to the project: we assume the Makefile including this file +# is in the project directory +ifndef PROJECT_PATH PROJECT_PATH := $(abspath $(dir $(firstword $(MAKEFILE_LIST)))) export PROJECT_PATH endif -#The directory where we put all objects/libraries/binaries. The project Makefile can -#configure this if needed. -BUILD_DIR_BASE ?= $(PROJECT_PATH)/build +# A list of the "common" makefiles, to use as a target dependency +COMMON_MAKEFILES := $(abspath $(IDF_PATH)/make/project.mk $(IDF_PATH)/make/common.mk $(IDF_PATH)/make/component_wrapper.mk) +export COMMON_MAKEFILES -#Component directories. These directories are searched for components. -#The project Makefile can override these component dirs, or define extra component directories. +# The directory where we put all objects/libraries/binaries. The project Makefile can +# configure this if needed. +BUILD_DIR_BASE ?= $(PROJECT_PATH)/build +export BUILD_DIR_BASE + +# Component directories. These directories are searched for components. +# The project Makefile can override these component dirs, or define extra component directories. COMPONENT_DIRS ?= $(PROJECT_PATH)/components $(EXTRA_COMPONENT_DIRS) $(IDF_PATH)/components export COMPONENT_DIRS -#The project Makefile can define a list of components, but if it does not do this we just take -#all available components in the component dirs. -ifeq ("$(COMPONENTS)","") -#Find all component names. The component names are the same as the -#directories they're in, so /bla/components/mycomponent/ -> mycomponent. We later use -#the COMPONENT_DIRS bit to find back the component path. +# Source directories of the project itself (a special, project-specific component.) Defaults to only "main". +SRCDIRS ?= main + +# The project Makefile can define a list of components, but if it does not do this we just take +# all available components in the component dirs. +ifndef COMPONENTS +# Find all component names. The component names are the same as the +# directories they're in, so /bla/components/mycomponent/ -> mycomponent. We then use +# COMPONENT_DIRS to build COMPONENT_PATHS with the full path to each component. COMPONENTS := $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/*)) COMPONENTS := $(sort $(foreach comp,$(COMPONENTS),$(lastword $(subst /, ,$(comp))))) endif export COMPONENTS -#Sources default to only "main" -SRCDIRS ?= main - -#Here, we resolve and add all the components and source paths into absolute paths. -#If a component exists in multiple COMPONENT_DIRS, we take the first match. -#WARNING: These directories paths must be generated WITHOUT a trailing / so we -#can use $(notdir x) to get the component name. +# Resolve all of COMPONENTS into absolute paths in COMPONENT_PATHS. +# +# If a component name exists in multiple COMPONENT_DIRS, we take the first match. +# +# NOTE: These paths must be generated WITHOUT a trailing / so we +# can use $(notdir x) to get the component name. COMPONENT_PATHS := $(foreach comp,$(COMPONENTS),$(firstword $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/$(comp))))) COMPONENT_PATHS += $(abspath $(SRCDIRS)) -#A component is buildable if it has a component.mk makefile; we assume that a -# 'make -C $(component dir) -f component.mk build' results in a lib$(componentname).a +# A component is buildable if it has a component.mk makefile in it COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/component.mk),$(cp))) -# Assemble global list of include dirs (COMPONENT_INCLUDES), and -# LDFLAGS args (COMPONENT_LDFLAGS) supplied by each component. +# Initialise a project-wide list of include dirs (COMPONENT_INCLUDES), +# and LDFLAGS args (COMPONENT_LDFLAGS) supplied by each component. +# +# These variables are built up via the component_project_vars.mk +# generated makefiles (one per component). COMPONENT_INCLUDES := COMPONENT_LDFLAGS := -# -# Also add any inter-component dependencies for each component. -# Extract a variable from a child make process +# COMPONENT_PROJECT_VARS is the list of component_project_vars.mk generated makefiles +# for each component. # -# $(1) - path to directory to invoke make in -# $(2) - name of variable to print via the get_variable target (passed in GET_VARIABLE) +# Including $(COMPONENT_PROJECT_VARS) builds the COMPONENT_INCLUDES, +# COMPONENT_LDFLAGS variables and also targets for any inter-component +# dependencies. # -# needs 'sed' processing of stdout because make sometimes echoes other stuff on stdout, -# even if asked not to. -# -# Debugging this? Replace $(shell with $(error and you'll see the full command as-run. -define GetVariable -$(shell "$(MAKE)" -s --no-print-directory -C $(1) -f component.mk get_variable PROJECT_PATH=$(PROJECT_PATH) GET_VARIABLE=$(2) | sed -En "s/^$(2)=(.+)/\1/p" ) -endef +# See the component_project_vars.mk target in component_wrapper.mk +COMPONENT_PROJECT_VARS := $(addsuffix /component_project_vars.mk,$(notdir $(COMPONENT_PATHS_BUILDABLE))) +COMPONENT_PROJECT_VARS := $(addprefix $(BUILD_DIR_BASE)/,$(COMPONENT_PROJECT_VARS)) +# this line is -include instead of include to prevent a spurious error message on make 3.81 +-include $(COMPONENT_PROJECT_VARS) -COMPONENT_INCLUDES := $(abspath $(foreach comp,$(COMPONENT_PATHS_BUILDABLE),$(addprefix $(comp)/, \ - $(call GetVariable,$(comp),COMPONENT_ADD_INCLUDEDIRS)))) +# Also add top-level project include path, for top-level includes +COMPONENT_INCLUDES += $(abspath $(BUILD_DIR_BASE)/include/) -#Also add project include path, for sdk includes -COMPONENT_INCLUDES += $(PROJECT_PATH)/build/include/ export COMPONENT_INCLUDES -#COMPONENT_LDFLAGS has a list of all flags that are needed to link the components together. It's collected -#in the same way as COMPONENT_INCLUDES is. -COMPONENT_LDFLAGS := $(foreach comp,$(COMPONENT_PATHS_BUILDABLE), \ - $(call GetVariable,$(comp),COMPONENT_ADD_LDFLAGS)) -export COMPONENT_LDFLAGS +# Set variables common to both project & component +include $(IDF_PATH)/make/common.mk -# Generate component dependency targets from dependencies lists -# each component gains a target of its own -build with dependencies -# of the names of any other components (-build) that need building first -# -# the actual targets (that invoke submakes) are generated below by -# GenerateComponentTarget macro. -define GenerateComponentDependencies -# $(1) = component path -.PHONY: $$(notdir $(1)) -$$(notdir $(1))-build: $(addsuffix -build,$(call GetVariable,$(1),COMPONENT_DEPENDS)) -endef -$(foreach comp,$(COMPONENT_PATHS_BUILDABLE), $(eval $(call GenerateComponentDependencies,$(comp)))) - -#Make sure submakes can also use this. -export PROJECT_PATH - -#Include functionality common to both project & component --include $(IDF_PATH)/make/common.mk +all: +ifdef CONFIG_SECURE_BOOTLOADER_ENABLED + @echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)" + @echo "To flash app & partition table, run 'make flash' or:" +else + @echo "To flash all build output, run 'make flash' or:" +endif + @echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) # Set default LDFLAGS @@ -140,6 +139,7 @@ LDFLAGS ?= -nostdlib \ -L$(IDF_PATH)/ld \ $(addprefix -L$(BUILD_DIR_BASE)/,$(COMPONENTS) $(SRCDIRS)) \ -u call_user_start_cpu0 \ + $(EXTRA_LDFLAGS) \ -Wl,--gc-sections \ -Wl,-static \ -Wl,--start-group \ @@ -149,34 +149,74 @@ LDFLAGS ?= -nostdlib \ -Wl,-EL # Set default CPPFLAGS, CFLAGS, CXXFLAGS -# # These are exported so that components can use them when compiling. -# # If you need your component to add CFLAGS/etc for it's own source compilation only, set CFLAGS += in your component's Makefile. -# # If you need your component to add CFLAGS/etc globally for all source -# files, set CFLAGS += in your component's Makefile.projbuild +# files, set CFLAGS += in your component's Makefile.projbuild +# If you need to set CFLAGS/CPPFLAGS/CXXFLAGS at project level, set them in application Makefile +# before including project.mk. Default flags will be added before the ones provided in application Makefile. -# CPPFLAGS used by an compile pass that uses the C preprocessor -CPPFLAGS = -DESP_PLATFORM -Og -g3 -Wpointer-arith -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable \ - -Wno-error=unused-variable -Wall -ffunction-sections -fdata-sections -mlongcalls -nostdlib -MMD -MP +# CPPFLAGS used by C preprocessor +# If any flags are defined in application Makefile, add them at the end. +CPPFLAGS := -DESP_PLATFORM $(CPPFLAGS) -# C flags use by C only -CFLAGS = $(CPPFLAGS) -std=gnu99 -g3 -fstrict-volatile-bitfields +# Warnings-related flags relevant both for C and C++ +COMMON_WARNING_FLAGS = -Wall -Werror \ + -Wno-error=unused-function \ + -Wno-error=unused-but-set-variable \ + -Wno-error=unused-variable \ + -Wno-error=deprecated-declarations -# CXXFLAGS uses by C++ only -CXXFLAGS = $(CPPFLAGS) -Og -std=gnu++11 -g3 -fno-exceptions -fstrict-volatile-bitfields -fno-rtti +# Flags which control code generation and dependency generation, both for C and C++ +COMMON_FLAGS = \ + -ffunction-sections -fdata-sections \ + -fstrict-volatile-bitfields \ + -mlongcalls \ + -nostdlib \ + -MMD -MP + +# Optimization flags are set based on menuconfig choice +ifneq ("$(CONFIG_OPTIMIZATION_LEVEL_RELEASE)","") +OPTIMIZATION_FLAGS = -Os +CPPFLAGS += -DNDEBUG +else +OPTIMIZATION_FLAGS = -Og +endif + +# Enable generation of debugging symbols +OPTIMIZATION_FLAGS += -ggdb + +# List of flags to pass to C compiler +# If any flags are defined in application Makefile, add them at the end. +CFLAGS := $(strip \ + -std=gnu99 \ + $(OPTIMIZATION_FLAGS) \ + $(COMMON_FLAGS) \ + $(COMMON_WARNING_FLAGS) \ + $(CFLAGS)) + +# List of flags to pass to C++ compiler +# If any flags are defined in application Makefile, add them at the end. +CXXFLAGS := $(strip \ + -std=gnu++11 \ + -fno-exceptions \ + -fno-rtti \ + $(OPTIMIZATION_FLAGS) \ + $(COMMON_FLAGS) \ + $(COMMON_WARNING_FLAGS) \ + $(CXXFLAGS)) export CFLAGS CPPFLAGS CXXFLAGS -#Set host compiler and binutils +# Set host compiler and binutils HOSTCC := $(CC) HOSTLD := $(LD) HOSTAR := $(AR) HOSTOBJCOPY := $(OBJCOPY) +export HOSTCC HOSTLD HOSTAR HOSTOBJCOPY -#Set target compiler. Defaults to whatever the user has -#configured as prefix + yer olde gcc commands +# Set target compiler. Defaults to whatever the user has +# configured as prefix + ye olde gcc commands CC := $(call dequote,$(CONFIG_TOOLPREFIX))gcc CXX := $(call dequote,$(CONFIG_TOOLPREFIX))c++ LD := $(call dequote,$(CONFIG_TOOLPREFIX))ld @@ -200,8 +240,12 @@ COMPONENT_PATH := $(1) endef $(foreach componentpath,$(COMPONENT_PATHS),$(eval $(call includeProjBuildMakefile,$(componentpath)))) -# once we know component paths, we can include the config +# once we know component paths, we can include the config generation targets +# +# (bootloader build doesn't need this, config is exported from top-level) +ifndef IS_BOOTLOADER_BUILD include $(IDF_PATH)/make/project_config.mk +endif # A "component" library is any library in the LDFLAGS where # the name of the library is also a name of the component @@ -212,7 +256,7 @@ COMPONENT_LIBRARIES = $(filter $(notdir $(COMPONENT_PATHS_BUILDABLE)),$(APP_LIBR # the rules to build these are emitted as part of GenerateComponentTarget below $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp)/lib$(libcomp).a) $(summary) LD $(notdir $@) - $(Q) $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) + $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) # Generation of $(APP_BIN) from $(APP_ELF) is added by the esptool # component's Makefile.projbuild @@ -225,36 +269,63 @@ all_binaries: $(APP_BIN) $(BUILD_DIR_BASE): mkdir -p $(BUILD_DIR_BASE) -define GenerateComponentPhonyTarget -# $(1) - path to component dir -# $(2) - target to generate (build, clean) -.PHONY: $(notdir $(1))-$(2) -$(notdir $(1))-$(2): | $(BUILD_DIR_BASE)/$(notdir $(1)) - @+$(MAKE) -C $(BUILD_DIR_BASE)/$(notdir $(1)) -f $(1)/component.mk COMPONENT_BUILD_DIR=$(BUILD_DIR_BASE)/$(notdir $(1)) $(2) +# Macro for the recursive sub-make for each component +# $(1) - component directory +# $(2) - component name only +# +# Is recursively expanded by the GenerateComponentTargets macro +define ComponentMake ++$(MAKE) -C $(BUILD_DIR_BASE)/$(2) -f $(IDF_PATH)/make/component_wrapper.mk COMPONENT_MAKEFILE=$(1)/component.mk endef -define GenerateComponentTargets +# Generate top-level component-specific targets for each component # $(1) - path to component dir -$(BUILD_DIR_BASE)/$(notdir $(1)): - @mkdir -p $(BUILD_DIR_BASE)/$(notdir $(1)) +# $(2) - name of component +# +define GenerateComponentTargets +.PHONY: $(2)-build $(2)-clean -# tell make it can build any component's library by invoking the recursive -build target +$(2)-build: + $(call ComponentMake,$(1),$(2)) build + +$(2)-clean: + $(call ComponentMake,$(1),$(2)) clean + +$(BUILD_DIR_BASE)/$(2): + @mkdir -p $(BUILD_DIR_BASE)/$(2) + +# tell make it can build any component's library by invoking the -build target # (this target exists for all components even ones which don't build libraries, but it's # only invoked for the targets whose libraries appear in COMPONENT_LIBRARIES and hence the # APP_ELF dependencies.) -$(BUILD_DIR_BASE)/$(notdir $(1))/lib$(notdir $(1)).a: $(notdir $(1))-build +$(BUILD_DIR_BASE)/$(2)/lib$(2).a: $(2)-build $(details) "Target '$$^' responsible for '$$@'" # echo which build target built this file + +# add a target to generate the component_project_vars.mk files that +# are used to inject variables into project make pass (see matching +# component_project_vars.mk target in component_wrapper.mk). +# +# If any component_project_vars.mk file is out of date, the make +# process will call this target to rebuild it and then restart. +# +# Note: $(SDKCONFIG) is a normal prereq as we need to rebuild these +# files whenever the config changes. $(SDKCONFIG_MAKEFILE) is an +# order-only prereq because if it hasn't been rebuilt, we need to +# build it first - but including it as a normal prereq can lead to +# infinite restarts as the conf process will keep updating it. +$(BUILD_DIR_BASE)/$(2)/component_project_vars.mk: $(1)/component.mk $(COMMON_MAKEFILES) $(SDKCONFIG) | $(BUILD_DIR_BASE)/$(2) $(SDKCONFIG_MAKEFILE) + $(call ComponentMake,$(1),$(2)) component_project_vars.mk endef -$(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentTargets,$(component)))) - -$(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentPhonyTarget,$(component),build))) -$(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentPhonyTarget,$(component),clean))) +$(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentTargets,$(component),$(notdir $(component))))) app-clean: $(addsuffix -clean,$(notdir $(COMPONENT_PATHS_BUILDABLE))) $(summary) RM $(APP_ELF) - $(Q) rm -f $(APP_ELF) $(APP_BIN) $(APP_MAP) + rm -f $(APP_ELF) $(APP_BIN) $(APP_MAP) -clean: app-clean +# NB: this ordering is deliberate (app-clean before config-clean), +# so config remains valid during all component clean targets +config-clean: app-clean +clean: config-clean diff --git a/make/project_config.mk b/make/project_config.mk index d2909bb308..a32c74a380 100644 --- a/make/project_config.mk +++ b/make/project_config.mk @@ -7,38 +7,42 @@ COMPONENT_KCONFIGS_PROJBUILD := $(foreach component,$(COMPONENT_PATHS),$(wildcar #For doing make menuconfig etc KCONFIG_TOOL_DIR=$(IDF_PATH)/tools/kconfig -# clear MAKEFLAGS as the menuconfig makefile uses implicit compile rules +# set SDKCONFIG to the project's sdkconfig, +# unless it's overriden (happens for bootloader) +SDKCONFIG ?= $(PROJECT_PATH)/sdkconfig + +# reset MAKEFLAGS as the menuconfig makefile uses implicit compile rules $(KCONFIG_TOOL_DIR)/mconf $(KCONFIG_TOOL_DIR)/conf: - MAKEFLAGS="" \ - CC=$(HOSTCC) LD=$(HOSTLD) \ + MAKEFLAGS=$(ORIGINAL_MAKEFLAGS) CC=$(HOSTCC) LD=$(HOSTLD) \ $(MAKE) -C $(KCONFIG_TOOL_DIR) -menuconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig $(BUILD_DIR_BASE) - $(summary) MENUCONFIG - $(Q) KCONFIG_AUTOHEADER=$(PROJECT_PATH)/build/include/sdkconfig.h \ - KCONFIG_CONFIG=$(PROJECT_PATH)/sdkconfig \ - COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" \ - COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)" \ - $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig +# use a wrapper environment for where we run Kconfig tools +KCONFIG_TOOL_ENV=KCONFIG_AUTOHEADER=$(abspath $(BUILD_DIR_BASE)/include/sdkconfig.h) \ + COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" KCONFIG_CONFIG=$(SDKCONFIG) \ + COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)" -ifeq ("$(wildcard $(PROJECT_PATH)/sdkconfig)","") -#No sdkconfig found. Need to run menuconfig to make this if we need it. -$(PROJECT_PATH)/sdkconfig: menuconfig +menuconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig + $(summary) MENUCONFIG + $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig + +ifeq ("$(wildcard $(SDKCONFIG))","") +ifeq ("$(filter defconfig,$(MAKECMDGOALS))","") +# if not configuration is present and defconfig is not a target, run makeconfig +$(SDKCONFIG): menuconfig +else +$(SDKCONFIG): defconfig +endif endif defconfig: $(KCONFIG_TOOL_DIR)/mconf $(IDF_PATH)/Kconfig $(BUILD_DIR_BASE) $(summary) DEFCONFIG - $(Q) mkdir -p $(PROJECT_PATH)/build/include/config - $(Q) KCONFIG_AUTOHEADER=$(PROJECT_PATH)/build/include/sdkconfig.h \ - KCONFIG_CONFIG=$(PROJECT_PATH)/sdkconfig \ - COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" \ - COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)" \ - $(KCONFIG_TOOL_DIR)/conf --olddefconfig $(IDF_PATH)/Kconfig + mkdir -p $(BUILD_DIR_BASE)/include/config + $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/conf --olddefconfig $(IDF_PATH)/Kconfig # Work out of whether we have to build the Kconfig makefile # (auto.conf), or if we're in a situation where we don't need it -NON_CONFIG_TARGETS := clean %-clean get_variable help menuconfig defconfig -AUTO_CONF_REGEN_TARGET := $(PROJECT_PATH)/build/include/config/auto.conf +NON_CONFIG_TARGETS := clean %-clean help menuconfig defconfig +AUTO_CONF_REGEN_TARGET := $(SDKCONFIG_MAKEFILE) # disable AUTO_CONF_REGEN_TARGET if all targets are non-config targets # (and not building default target) @@ -46,26 +50,21 @@ ifneq ("$(MAKECMDGOALS)","") ifeq ($(filter $(NON_CONFIG_TARGETS), $(MAKECMDGOALS)),$(MAKECMDGOALS)) AUTO_CONF_REGEN_TARGET := # dummy target -$(PROJECT_PATH)/build/include/config/auto.conf: +$(SDKCONFIG_MAKEFILE): endif endif -$(AUTO_CONF_REGEN_TARGET) $(PROJECT_PATH)/build/include/sdkconfig.h: $(PROJECT_PATH)/sdkconfig $(KCONFIG_TOOL_DIR)/conf $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD) +$(AUTO_CONF_REGEN_TARGET) $(BUILD_DIR_BASE)/include/sdkconfig.h: $(SDKCONFIG) $(KCONFIG_TOOL_DIR)/conf $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD) $(summary) GENCONFIG - $(Q) mkdir -p $(PROJECT_PATH)/build/include/config - $(Q) cd build; KCONFIG_AUTOHEADER="$(PROJECT_PATH)/build/include/sdkconfig.h" \ - KCONFIG_CONFIG=$(PROJECT_PATH)/sdkconfig \ - COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" \ - COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)" \ - $(KCONFIG_TOOL_DIR)/conf --silentoldconfig $(IDF_PATH)/Kconfig - $(Q) touch $(AUTO_CONF_REGEN_TARGET) $(PROJECT_PATH)/build/include/sdkconfig.h + mkdir -p $(BUILD_DIR_BASE)/include/config + cd $(BUILD_DIR_BASE); $(KCONFIG_TOOL_ENV) $(KCONFIG_TOOL_DIR)/conf --silentoldconfig $(IDF_PATH)/Kconfig + touch $(AUTO_CONF_REGEN_TARGET) $(BUILD_DIR_BASE)/include/sdkconfig.h # touch to ensure both output files are newer - as 'conf' can also update sdkconfig (a dependency). Without this, # sometimes you can get an infinite make loop on Windows where sdkconfig always gets regenerated newer # than the target(!) -clean: config-clean .PHONY: config-clean config-clean: $(summary RM CONFIG) $(MAKE) -C $(KCONFIG_TOOL_DIR) clean - $(Q) rm -rf $(PROJECT_PATH)/build/include/config $(PROJECT_PATH)/build/include/sdkconfig.h + rm -rf $(BUILD_DIR_BASE)/include/config $(BUILD_DIR_BASE)/include/sdkconfig.h diff --git a/make/test_build_system.sh b/make/test_build_system.sh index 5be1504e3d..d08ae6c8a2 100755 --- a/make/test_build_system.sh +++ b/make/test_build_system.sh @@ -2,7 +2,7 @@ # # Test the build system for basic consistency # -# Just a bash script that tests some likely make failure scenarios in a row +# A bash script that tests some likely make failure scenarios in a row # Creates its own test build directory under TMP and cleans it up when done. # # Environment variables: @@ -11,6 +11,18 @@ # ESP_IDF_TEMPLATE_GIT - Can override git clone source for template app. Otherwise github. # NOCLEANUP - Set to '1' if you want the script to leave its temporary directory when done, for post-mortem. # +# +# Internals: +# * The tests run in sequence & the system keeps track of all failures to print at the end. +# * BUILD directory is set to default BUILD_DIR_BASE +# * The "print_status" function both prints a status line to the log and keeps track of which test is running. +# * Calling the "failure" function prints a failure message to the log and also adds to the list of failures to print at the end. +# * The function "assert_built" tests for a file relative to the BUILD directory. +# * The function "take_build_snapshot" can be paired with the functions "assert_rebuilt" and "assert_not_rebuilt" to compare file timestamps and verify if they were rebuilt or not since the snapshot was taken. +# +# To add a new test case, add it to the end of the run_tests function. Note that not all test cases do comprehensive cleanup +# (although very invasive ones like appending CRLFs to all files take a copy of the esp-idf tree), however the clean_build_dir +# function can be used to force-delete all files from the build output directory. # Set up some variables # @@ -21,103 +33,137 @@ export V=1 function run_tests() { - FAILURES= - STATUS="Starting" - print_status "Checking prerequisites" - [ -z ${IDF_PATH} ] && echo "IDF_PATH is not set. Need path to esp-idf installation." && exit 2 + FAILURES= + STATUS="Starting" + print_status "Checking prerequisites" + [ -z ${IDF_PATH} ] && echo "IDF_PATH is not set. Need path to esp-idf installation." && exit 2 - print_status "Cloning template from ${ESP_IDF_TEMPLATE_GIT}..." - git clone ${ESP_IDF_TEMPLATE_GIT} template - cd template - git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..." + print_status "Cloning template from ${ESP_IDF_TEMPLATE_GIT}..." + git clone ${ESP_IDF_TEMPLATE_GIT} template + cd template + git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..." - print_status "Updating template config..." - make defconfig || exit $? + print_status "Updating template config..." + make defconfig || exit $? - BOOTLOADER_BINS="bootloader/bootloader.elf bootloader/bootloader.bin" - APP_BINS="app-template.elf app-template.bin" + BOOTLOADER_BINS="bootloader/bootloader.elf bootloader/bootloader.bin" + APP_BINS="app-template.elf app-template.bin" - print_status "Initial clean build" - # if make fails here, everything fails - make || exit $? - # check all the expected build artifacts from the clean build - assert_built ${APP_BINS} ${BOOTLOADER_BINS} partitions_singleapp.bin - [ -f ${BUILD}/partition*.bin ] || failure "A partition table should have been built" + print_status "Initial clean build" + # if make fails here, everything fails + make || exit $? + # check all the expected build artifacts from the clean build + assert_built ${APP_BINS} ${BOOTLOADER_BINS} partitions_singleapp.bin + [ -f ${BUILD}/partition*.bin ] || failure "A partition table should have been built" - print_status "Updating component source file rebuilds component" - # touch a file & do a build - take_build_snapshot - touch ${IDF_PATH}/components/esp32/syscalls.c - make || failure "Failed to partial build" - assert_rebuilt ${APP_BINS} esp32/libesp32.a esp32/syscalls.o - assert_not_rebuilt lwip/liblwip.a freertos/libfreertos.a ${BOOTLOADER_BINS} partitions_singleapp.bin + print_status "Updating component source file rebuilds component" + # touch a file & do a build + take_build_snapshot + touch ${IDF_PATH}/components/esp32/cpu_start.c + make || failure "Failed to partial build" + assert_rebuilt ${APP_BINS} esp32/libesp32.a esp32/cpu_start.o + assert_not_rebuilt lwip/liblwip.a freertos/libfreertos.a ${BOOTLOADER_BINS} partitions_singleapp.bin - print_status "Bootloader source file rebuilds bootloader" - take_build_snapshot - touch ${IDF_PATH}/components/bootloader/src/main/bootloader_start.c - make bootloader || failure "Failed to partial build bootloader" - assert_rebuilt ${BOOTLOADER_BINS} bootloader/main/bootloader_start.o - assert_not_rebuilt ${APP_BINS} partitions_singleapp.bin + print_status "Bootloader source file rebuilds bootloader" + take_build_snapshot + touch ${IDF_PATH}/components/bootloader/src/main/bootloader_start.c + make bootloader || failure "Failed to partial build bootloader" + assert_rebuilt ${BOOTLOADER_BINS} bootloader/main/bootloader_start.o + assert_not_rebuilt ${APP_BINS} partitions_singleapp.bin - print_status "Partition CSV file rebuilds partitions" - take_build_snapshot - touch ${IDF_PATH}/components/partition_table/partitions_singleapp.csv - make partition_table - assert_rebuilt partitions_singleapp.bin - assert_not_rebuilt app-template.bin app-template.elf ${BOOTLOADER_BINS} + print_status "Partition CSV file rebuilds partitions" + take_build_snapshot + touch ${IDF_PATH}/components/partition_table/partitions_singleapp.csv + make partition_table || failure "Failed to build partition table" + assert_rebuilt partitions_singleapp.bin + assert_not_rebuilt app-template.bin app-template.elf ${BOOTLOADER_BINS} - print_status "Partial build doesn't compile anything by default" - take_build_snapshot - # verify no build files are refreshed by a partial make - ALL_BUILD_FILES=$(find ${BUILD} -type f | sed "s@${BUILD}/@@") - make - assert_not_rebuilt ${ALL_BUILD_FILES} + print_status "Partial build doesn't compile anything by default" + take_build_snapshot + # verify no build files are refreshed by a partial make + ALL_BUILD_FILES=$(find ${BUILD} -type f | sed "s@${BUILD}/@@") + make || failure "Partial build failed" + assert_not_rebuilt ${ALL_BUILD_FILES} - print_status "Cleaning should remove all files from build" - make clean - ALL_BUILD_FILES=$(find ${BUILD} -type f) - if [ -n "${ALL_BUILD_FILES}" ]; then - failure "Files weren't cleaned: ${ALL_BUILD_FILES}" - fi + print_status "Cleaning should remove all files from build" + make clean || failure "Failed to make clean" + ALL_BUILD_FILES=$(find ${BUILD} -type f) + if [ -n "${ALL_BUILD_FILES}" ]; then + failure "Files weren't cleaned: ${ALL_BUILD_FILES}" + fi - print_status "Can still clean build if all text files are CRLFs" - make clean - find . -exec unix2dos {} \; # CRLFify template dir - # make a copy of esp-idf and CRLFify it - CRLF_ESPIDF=${TESTDIR}/esp-idf-crlf - mkdir -p ${CRLF_ESPIDF} - cp -rv ${IDF_PATH}/* ${CRLF_ESPIDF} - # don't CRLFify executable files, as Linux will fail to execute them - find ${CRLF_ESPIDF} -type f ! -perm 755 -exec unix2dos {} \; - make IDF_PATH=${CRLF_ESPIDF} - # do the same checks we do for the clean build - assert_built ${APP_BINS} ${BOOTLOADER_BINS} partitions_singleapp.bin - [ -f ${BUILD}/partition*.bin ] || failure "A partition table should have been built in CRLF mode" + print_status "Bootloader build shouldn't leave build output anywhere else" + clean_build_dir + make bootloader + # find wizardry: find any file not named sdkconfig.h that + # isn't in the "bootloader" or "config" directories + find ${BUILD} -type d \( -name bootloader -o -name config \) -prune , -type f ! -name sdkconfig.h || failure "Bootloader built files outside the bootloader or config directories" - # NOTE: If adding new tests, add them above this CRLF test... + print_status "Moving BUILD_DIR_BASE out of tree" + clean_build_dir + OUTOFTREE_BUILD=${TESTDIR}/alt_build + make BUILD_DIR_BASE=${OUTOFTREE_BUILD} || failure "Failed to build with BUILD_DIR_BASE overriden" + NEW_BUILD_FILES=$(find ${OUTOFREE_BUILD} -type f) + if [ -z "${NEW_BUILD_FILES}" ]; then + failure "No files found in new build directory!" + fi + DEFAULT_BUILD_FILES=$(find ${BUILD} -mindepth 1) + if [ -n "${DEFAULT_BUILD_FILES}" ]; then + failure "Some files were incorrectly put into the default build directory: ${DEFAULT_BUILD_FILES}" + fi - print_status "All tests completed" - if [ -n "${FAILURES}" ]; then - echo "Some failures were detected:" - echo -e "${FAILURES}" - exit 1 - else - echo "Build tests passed." - fi + print_status "BUILD_DIR_BASE inside default build directory" + clean_build_dir + make BUILD_DIR_BASE=build/subdirectory || failure "Failed to build with BUILD_DIR_BASE as subdir" + NEW_BUILD_FILES=$(find ${BUILD}/subdirectory -type f) + if [ -z "${NEW_BUILD_FILES}" ]; then + failure "No files found in new build directory!" + fi + + print_status "Parallel builds should work OK" + clean_build_dir + (make -j5 2>&1 | tee ${TESTDIR}/parallel_build.log) || failure "Failed to build in parallel" + if grep -q "warning: jobserver unavailable" ${TESTDIR}/parallel_build.log; then + failure "Parallel build prints 'warning: jobserver unavailable' errors" + fi + + print_status "Can still clean build if all text files are CRLFs" + make clean || failure "Unexpected failure to make clean" + find . -exec unix2dos {} \; # CRLFify template dir + # make a copy of esp-idf and CRLFify it + CRLF_ESPIDF=${TESTDIR}/esp-idf-crlf + mkdir -p ${CRLF_ESPIDF} + cp -rv ${IDF_PATH}/* ${CRLF_ESPIDF} + # don't CRLFify executable files, as Linux will fail to execute them + find ${CRLF_ESPIDF} -type f ! -perm 755 -exec unix2dos {} \; + make IDF_PATH=${CRLF_ESPIDF} || failure "Failed to build with CRLFs in source" + # do the same checks we do for the clean build + assert_built ${APP_BINS} ${BOOTLOADER_BINS} partitions_singleapp.bin + [ -f ${BUILD}/partition*.bin ] || failure "A partition table should have been built in CRLF mode" + + + print_status "All tests completed" + if [ -n "${FAILURES}" ]; then + echo "Some failures were detected:" + echo -e "${FAILURES}" + exit 1 + else + echo "Build tests passed." + fi } function print_status() { - echo "******** $1" - STATUS="$1" + echo "******** $1" + STATUS="$1" } function failure() { - echo "!!!!!!!!!!!!!!!!!!!" - echo "FAILURE: $1" - echo "!!!!!!!!!!!!!!!!!!!" - FAILURES="${FAILURES}${STATUS} :: $1\n" + echo "!!!!!!!!!!!!!!!!!!!" + echo "FAILURE: $1" + echo "!!!!!!!!!!!!!!!!!!!" + FAILURES="${FAILURES}${STATUS} :: $1\n" } TESTDIR=${TMP}/build_system_tests_$$ @@ -133,62 +179,68 @@ BUILD=${TESTDIR}/template/build # copy all the build output to a snapshot directory function take_build_snapshot() { - rm -rf ${SNAPSHOT} - cp -ap ${TESTDIR}/template/build ${SNAPSHOT} + rm -rf ${SNAPSHOT} + cp -ap ${TESTDIR}/template/build ${SNAPSHOT} } # verify that all the arguments are present in the build output directory function assert_built() { - until [ -z "$1" ]; do - if [ ! -f "${BUILD}/$1" ]; then - failure "File $1 should be in the build output directory" - fi - shift - done + until [ -z "$1" ]; do + if [ ! -f "${BUILD}/$1" ]; then + failure "File $1 should be in the build output directory" + fi + shift + done } # Test if a file has been rebuilt. function file_was_rebuilt() { - # can't use [ a -ot b ] here as -ot only gives second resolution - # but stat -c %y seems to be microsecond at least for tmpfs, ext4.. - if [ "$(stat -c %y ${SNAPSHOT}/$1)" != "$(stat -c %y ${BUILD}/$1)" ]; then - return 0 - else - return 1 - fi + # can't use [ a -ot b ] here as -ot only gives second resolution + # but stat -c %y seems to be microsecond at least for tmpfs, ext4.. + if [ "$(stat -c %y ${SNAPSHOT}/$1)" != "$(stat -c %y ${BUILD}/$1)" ]; then + return 0 + else + return 1 + fi } # verify all the arguments passed in were rebuilt relative to the snapshot function assert_rebuilt() { - until [ -z "$1" ]; do - assert_built "$1" - if [ ! -f "${SNAPSHOT}/$1" ]; then - failure "File $1 should have been original build snapshot" - fi - if ! file_was_rebuilt "$1"; then - failure "File $1 should have been rebuilt" - fi - shift - done + until [ -z "$1" ]; do + assert_built "$1" + if [ ! -f "${SNAPSHOT}/$1" ]; then + failure "File $1 should have been original build snapshot" + fi + if ! file_was_rebuilt "$1"; then + failure "File $1 should have been rebuilt" + fi + shift + done } # verify all the arguments are in the build directory & snapshot, # but were not rebuilt function assert_not_rebuilt() { - until [ -z "$1" ]; do - assert_built "$1" - if [ ! -f "${SNAPSHOT}/$1" ]; then - failure "File $1 should be in snapshot build directory" - fi - if file_was_rebuilt "$1"; then - failure "File $1 should not have been rebuilt" - fi - shift - done + until [ -z "$1" ]; do + assert_built "$1" + if [ ! -f "${SNAPSHOT}/$1" ]; then + failure "File $1 should be in snapshot build directory" + fi + if file_was_rebuilt "$1"; then + failure "File $1 should not have been rebuilt" + fi + shift + done +} + +# do a "clean" that doesn't depend on 'make clean' +function clean_build_dir() +{ + rm -rf --preserve-root ${BUILD}/* } cd ${TESTDIR} diff --git a/tools/eclipse-code-style.xml b/tools/eclipse-code-style.xml new file mode 100644 index 0000000000..f589a00800 --- /dev/null +++ b/tools/eclipse-code-style.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/format-minimal.sh b/tools/format-minimal.sh new file mode 100644 index 0000000000..ff829247d3 --- /dev/null +++ b/tools/format-minimal.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Runs astyle with parameters which should be checked in a pre-commit hook +astyle \ + --style=otbs \ + --indent=spaces=4 \ + --convert-tabs \ + --keep-one-line-statements \ + --pad-header \ + "$@" diff --git a/tools/format.sh b/tools/format.sh new file mode 100644 index 0000000000..aadb337aaa --- /dev/null +++ b/tools/format.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Runs astyle with the full set of formatting options +astyle \ + --style=otbs \ + --indent=spaces=4 \ + --convert-tabs \ + --align-pointer=name \ + --align-reference=name \ + --keep-one-line-statements \ + --pad-header \ + --pad-oper \ + "$@" diff --git a/tools/kconfig/Makefile b/tools/kconfig/Makefile index fee5a69316..9680b74109 100644 --- a/tools/kconfig/Makefile +++ b/tools/kconfig/Makefile @@ -41,13 +41,13 @@ nconfig: nconf $< $(silent) $(Kconfig) silentoldconfig: conf - $(Q)mkdir -p include/config include/generated + mkdir -p include/config include/generated $< $(silent) --$@ $(Kconfig) localyesconfig localmodconfig: streamline_config.pl conf - $(Q)mkdir -p include/config include/generated - $(Q)perl $< --$@ . $(Kconfig) > .tmp.config - $(Q)if [ -f .config ]; then \ + mkdir -p include/config include/generated + perl $< --$@ . $(Kconfig) > .tmp.config + if [ -f .config ]; then \ cmp -s .tmp.config .config || \ (mv -f .config .config.old.1; \ mv -f .tmp.config .config; \ @@ -57,7 +57,7 @@ localyesconfig localmodconfig: streamline_config.pl conf mv -f .tmp.config .config; \ conf $(silent) --silentoldconfig $(Kconfig); \ fi - $(Q)rm -f .tmp.config + rm -f .tmp.config # These targets map 1:1 to the commandline options of 'conf' @@ -84,22 +84,22 @@ ifeq ($(KBUILD_DEFCONFIG),) else ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),) @$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'" - $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) + $< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) else @$(kecho) "*** Default configuration is based on target '$(KBUILD_DEFCONFIG)'" - $(Q) $(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG) + $(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG) endif endif %_defconfig: conf - $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) + $< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/configs/$@) %.config: conf $(if $(call configfiles),, $(error No configuration exists for this target on this architecture)) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles) - +$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig + $(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles) + +yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig PHONY += kvmconfig kvmconfig: kvm_guest.config @@ -111,7 +111,7 @@ xenconfig: xen.config PHONY += tinyconfig tinyconfig: - $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config + $(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config # Help text used by make help help: @@ -181,7 +181,7 @@ clean-files += $(conf-objs) $(mconf-objs) conf mconf $(lxdialog) PHONY += dochecklxdialog $(addprefix ,$(lxdialog)): dochecklxdialog dochecklxdialog: - $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(CC) $(CFLAGS) $(LOADLIBES_mconf) + $(CONFIG_SHELL) $(check-lxdialog) -check $(CC) $(CFLAGS) $(LOADLIBES_mconf) always := dochecklxdialog @@ -285,7 +285,7 @@ quiet_cmd_moc = MOC $@ # Extract gconf menu items for i18n support gconf.glade.h: gconf.glade - $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \ + intltool-extract --type=gettext/glade --srcdir=$(srctree) \ gconf.glade diff --git a/tools/kconfig/lxdialog/check-lxdialog.sh b/tools/kconfig/lxdialog/check-lxdialog.sh index 6964d2b0c5..79df5ed4f9 100755 --- a/tools/kconfig/lxdialog/check-lxdialog.sh +++ b/tools/kconfig/lxdialog/check-lxdialog.sh @@ -5,8 +5,8 @@ ldflags() { if [ $(uname -s) == "Darwin" ]; then - #OSX seems to need intl too - echo -n "-lintl " + #OSX seems to need ncurses too + echo -n "-lncurses " fi pkg-config --libs ncursesw 2>/dev/null && exit pkg-config --libs ncurses 2>/dev/null && exit @@ -41,6 +41,10 @@ ccflags() else echo '-DCURSES_LOC=""' fi + if [ $(uname -s) == "Darwin" ]; then + #OSX doesn't have libintl + echo -n "-DKBUILD_NO_NLS -Wno-format-security " + fi } # Temp file, try to clean up after us